Quantcast
Channel: Adictos al trabajo
Viewing all 989 articles
Browse latest View live

Cómo hacer fotos que ayuden a vender mejor tus productos

$
0
0

Cómo hacer fotos que ayuden a vender mejor tus productos

Índice de contenidos


1. Introducción

Todos conocemos el dicho de “una imagen vale más que mil palabras” y, cuando se trata de vender un producto o un servicio por catálogo o por internet a través de nuestra web, nuestro blog o nuestra tienda on line, el 80% de la venta vendrá impulsada por la fotografía que ilustre lo que el usuario está comprando. Muchas veces no damos importancia a la manera en que enseñamos nuestro producto a nuestros clientes y eso nos hace perder no sólo un número alto de ventas, sino también perdemos valor de marca. Y la marca es muy importante cuidarla.

¿Imaginas una tienda online sin fotos? ¿Una tienda física donde esconden los productos y solamente pudieras ver en un listado lo que tienen? ¿Imaginas un anuncio de televisión sin imágenes?

Hace no mucho leí el siguiente artículo: “Ebay demuestra como unas buenas fotos ayudan a vender más: En uno de los últimos estudios realizados por eBay, se analizó el comportamiento de 100 millones de usuarios, para determinar los elementos que permiten un mayor incremento en el precio de venta. Este estudio analizó 200 variables distintas, al mismo tiempo, generando 12 terabytes de datos al día, que posteriormente fueron analizados por eBay mediante técnicas de Big Data. Según Tom Fastner, arquitecto software principal de eBay, “Nos preguntábamos si la calidad de las fotografías en las páginas de categoría tenían impacto en el precio de venta. Analizamos unos cuantos Petabytes de imágenes gracias a Hadoop y pudimos determinar que la calidad de las imágenes tiene un impacto directo y muy importante sobre el precio de venta”. EBay nos deja claro que invertir en unas buenas imágenes de los productos nos permite obtener un incremento considerable en los beneficios por cada una de las ventas, por lo que se convierte en una inversión más que rentable.

Podemos hablar de tres estados de fotografía de producto:

  • Fotografía de “enseñar” el producto. Lo más parecido a hacer una foto con el móvil y mandarla a un amigo.
  • Fotografía profesional de producto. Fotos de estudio, hechas con una buena y pensada iluminación, que describen un producto con detalle y realzan sus cualidades. Es decir, fotos que venden.
  • Fotografía publicitaria. Nos manipula. Crea la necesidad de poseer sin renunciar a una buena descripción del producto. Lo queremos. Lo deseamos.

Pensad un momento en el marketing de Zara. Si entramos en su página web vemos que cada prenda tiene varias vistas y además hay una vista gigante de cada foto. Tardaron años en sacar su tienda online pero es, sin duda, el modelo a seguir. No les va nada mal en Internet.

Nos gusta ver. Vemos con los ojos. Somos visuales. Desde niños queremos verlo todo y tocarlo todo y cuanto más bonitas son las cosas o si están bien presentadas más nos atraen. Si vamos andando por la calle y vemos un escaparate impresionante seguramente nos detenemos a contemplarlo. En internet, una buena foto en una web puede detener el impulso de cerrar la página e invitarnos a seguir leyendo. ¿Cuántos discos habremos comprado por su portada, cuántas revistas habremos guardado por sus fotos bonitas?


2. Por qué es importante una buena foto de producto

¿Te has preguntado alguna vez por qué unas tiendas online con los mismos productos venden más que otras? La estrategia SEO y la inversión en publicidad lleva tráfico hasta la página, pero no vende. La reputación de una tienda online y su trato al cliente hará que se repita una compra, pero de entrada no vende.

Unos textos bien cuidados y siguiendo una estrategia SEO y comercial también ayuda a las ventas, pero sobre todo fideliza clientes y canaliza tráfico. Hay productos que «se venden solos», pero en unas páginas se venden más que en otras. ¿Por qué?

Gran parte del éxito de una tienda online, donde no puedes tocar lo que compras, está en su política de imágenes de catálogo. Unas buenas fotos de catálogo tranquilizan al futuro cliente, derriban la barrera de lo digital, le ayudan a decidirse.

Si las fotografías de los productos no dan la talla, perderemos ventas y mancharemos nuestra reputación. Si las vamos a realizar nosotros mismos, es muy importante que sepamos cómo debemos hacer las fotos de nuestros productos para que queden lo más profesionales posibles y nos ayuden a catapultar las ventas.

La primera premisa de la fotografía de productos y servicios es que sean lo más fieles posible a la realidad de los productos y servicios que vendemos porque si no podemos crear dos efectos negativos:

  • Falsas expectativas: Es decir, nunca debemos hacer fotos excesivamente retocadas que muestren un producto mucho mejor que el real, ya que cuando el usuario lo compre se sentirá decepcionado y mancharemos nuestra imagen y nuestra reputación.
  • Repeler: Es decir, nunca debemos publicar fotos cutres que muestren el producto peor de lo que es, ya que si el producto o el servicio no entra por la vista el usuario no lo comprará y además mancharemos nuestra imagen y nuestra reputación.

3. Consejos para una buena foto de producto

1. Trabaja la iluminación

La iluminación es clave para hacer fotografías profesionales que ayuden a vender tus productos. Por eso, antes de hacer las fotos añade luz extra con varios focos o lamparillas. Lo ideal es utilizar 3 focos de luz: a izquierda, derecha y otro para el fondo. Eso si, es muy importante difuminar la luz ya que sino puede quemar la imagen y/o se crearán sombras que pueden afear nuestros productos e incluso dejar zonas a oscuras. Lo ideal es no poner luces directas sobre nuestros productos.

2. Evita el flash

El flash tiene muchas virtudes, pero cuando hablamos de fotos de productos el flash cuanto más lejos mejor. La luz del flash es directa y produce una iluminación irregular, por lo que lo único que conseguiremos será afear nuestros productos con una luz intensa y blanquecina en una parte del producto.

3. Utiliza trípode

Usar un trípode nos ayudará a mejorar las fotografías de nuestros productos. De este modo, evitaremos que las fotografías nos salgan movidas, torcidas y nos será más fácil establecer los ángulos ideales para cada producto.

4. Centra el objeto y aprovecha al máximo el encuadre

El objeto es el protagonista, y como tal merece acaparar todo el espacio posible dentro de la foto. Por eso, aprovecha al máximo el encuadre y centra el producto en medio dejando únicamente unos pequeños márgenes de fondo alrededor del producto

5. Saca planos detalle

Todos los productos tienen muchos detalles: costuras, cierres, texturas, etc. Por eso, debemos hacer fotos también de todos los detalles que aporten valor al producto ya que ayudarán al usuario a hacerse una idea de la calidad, el tacto, el olor, etc. del producto que van a comprar.

6. Juega con los ángulos

Igual que las personas tenemos nuestro lado bueno, los productos también lo tienen. Por eso, debemos jugar con los ángulos buscando siempre encontrar la fotografía más descriptiva y más ilustrativa posible.

7. Céntrate en el producto que quieres vender

La mayoría de productos tienen suficiente fuerza como para venderse solos. Por eso, y como norma general, no cargues los productos con complementos, objetos decorativos, etc. ya que despistan al usuario y hacen que no se centre en el producto que quieres vender. Además, si añades otros productos complementarios en las fotografías puedes llevar a confusión a los usuarios, ya que pueden pensar que el complemento también forma parte del producto y esto te puede acarrear problemas de imagen, reputación, devoluciones, etc.

8. Muestra el uso del producto en la foto

Algunos productos necesitan un empujoncito para que vendan más. Es el caso de los productos que se llevan puestos, como ropa, complementos, etc. En estos casos, la mayoría de gente no quiere ver solo el producto, sino cómo queda puesto, ya que así se puede hacer una idea de cómo le quedará a él o a ella. Por eso, cuando queramos vender ropa y complementos lo más recomendable es hacer fotos con modelos, donde se vea cómo quedan los productos puestos.

9. Si no indicas las medidas del producto, aprovecha la foto para mostrar la escala

Otros productos, por ejemplo, necesitan una referencia de escala para que el usuario se pueda hacer a la idea del tamaño real de ese objeto. Por eso, en estos casos es muy recomendable incluir en la fotografía algún otro elemento que nos indique las medidas aproximadas del producto.

10. Saca imágenes en alta resolución

Independientemente de dónde vayas a utilizar las fotografías de los productos, sácalas siempre en alta resolución (300 ppp). Ten en cuenta que las fotografías en alta resolución se pueden reducir sin que pierdan calidad, pero las fotografías en baja resolución no se pueden ampliar.

11. Utiliza formato RAW

Siempre que puedas utiliza el formato RAW para hacer las fotografías de tus productos, ya que te ofrecen una mayor calidad y muchas más posibilidades de mejora en post producción con Photoshop, por ejemplo.

12. Retoca las fotos levemente

Una vez hechas las fotografías retoca levemente las fotos para mejorar el contraste, el brillo y la saturación. Pero no abuses de los retoques. Recuerda que deben quedar lo más fieles a la realidad posible.

13. Adapta la resolución de las fotos al medio donde las vas a usar

Aunque hagas las fotos en alta resolución luego debes adaptarlas al dispositivo o al medio en el que las vas a usar. Por eso, si vas a utilizar las fotografías en tu web o en tu tienda on line, redúcelas a 72 dpi para que no pesen en exceso. Recuerda que si tus fotos pesan demasiado tu web o tu tienda on line irán más lentas, y la lentitud de carga es una de las penalizaciones más comunes en el SEO.

14. Guarda la foto con un nombre descriptivo

Los buscadores son capaces de leer el nombre de las fotografías. Por eso, debemos guardarlas y subirlas con un nombre lo más descriptivo posible ya que así, además que nos será más fácil encontrarlas, ayudaremos a que tengan un mejor posicionamiento en los buscadores y ayudaremos a optimizar el SEO.

15. Evita las marcas de agua gigantes

Muchas empresas optan por añadir marcas de agua gigantes en sus fotografías con la finalidad de marcar su autoría y que otras empresas no las puedan usar. Sin embargo, cuando podemos una marca de agua grande sobre la foto evitamos que se vea el producto correctamente. Por eso, en vez de utilizar marcas de agua, es recomendable utilizar una firma en la parte inferior de los productos, ya que así marcamos la autoría de forma sutil y elegante. Y en el caso de que decidamos utilizar las marcas de agua en nuestras fotos debemos poner marcas de agua pequeñas y situadas en la parte inferior o superior de la fotografía para que los usuarios puedan ver sin problemas los productos que quieren comprar.

16. Haz fotos bonitas y creativas

Utiliza tu creatividad para realizar fotos bonitas, impactantes y seductoras, que consigan enamorar a los usuarios y ayudarte a posicionar tu marca en la mente de tu público potencial. No olvides que las fotografías de tus productos tienen que transmitir la esencia de tu marca.

Desde fotografías con fondo blanco con el producto aislado, a bodegones con puesta en escena donde se sitúa el producto en un pequeño decorado, resolver la iluminación puede llegar a ser un reto.

Os dejo un ejemplo de cómo fotografian una hamburguesa de Mcdonalds y su comparativa con una comprada en el establecimiento que me pareció interesante al verlo: https://www.youtube.com/watch?v=oSd0keSj2W8


Introspección y Reflexión en Java para testear clases de utilidades

$
0
0

En este tutorial vamos a ver la potencia de la introspección y reflexión en Java para hacer algo muy poco común: testear atributos de clases de utilidad.

1. Introducción

En los lenguajes dinámicos, como por ejemplo, Javascript, es posible alterar los objetos en tiempo de ejecución, sea cual sea su clase, añadiendo atributos o haciendo comprobaciones sobre ellos. Esto permite hacer algunas operaciones bastante creativas en nuestros desarrollos, o disponer de librerías que hacen “magia”.

Pero en los lenguajes estáticos como por ejemplo Java, esto ya es menos común: solemos partir de la base de que tenemos clases prácticamente inamovibles, de las cuales surgen los objetos, y tampoco nos suele cuadrar en la cabeza hacer algún tipo de consulta en tiempo de ejecución sobre sus atributos y propiedades, o directamente su modificación: no cuadra mucho con la programación orientada a objetos puramente dicha.

Como ya sabemos de sobra, Java es un lenguaje fuertemente tipado, pero esto no quiere decir que no permita hacer algunas operaciones especiales, ayudándose de dos conceptos:

  • Introspección: la capacidad para inspeccionar los metadatos de un objeto, como atributos, propiedades, visibilidad…
  • Reflexión: la capacidad para alterar en tiempo de ejecución los metadatos, como añadir atributos, alterar visibilidad…

En este tutorial vamos a usar estas dos capacidades de Java para poder hacer algo un poco “creativo”: testear si una clase de utilidad está correctamente especificada.

1.1 Advertencia.

Os advierto que en este tutorial voy a hacer unas cuantas cosas que seguramente hagan echarse las manos a la cabeza a los más puristas artesanos del software. Las enumero para que veáis que soy consciente de ello:

  • Las clases de utilidades no pueden considerarse Programación Orientada a Objetos pura y dura: son como un cajón de sastre donde van métodos que un mal diseño ha condenado a no pertenecer a ninguna clase.
  • El objetivo es testear si una clase privada es final, si su constructor es privado y si lanza una excepción si se intenta invocar: esto va en contra de la filosofía del agilismo, porque requiere un esfuerzo grande que no merece la pena porque no aporta valor alguno, salvo darse la satisfacción de testear todas las líneas del código, incluida alguna que jamás se podrá ejecutar.
  • La introspección y la reflexión son armas que deberían tratarse con mucho cuidado, y que podría cuestionarse su pertenencia a una programación orientada a objetos como debe de ser.

Así, que… tomaos a este tutorial como un ejercicio creativo de demostración!

2. Clases de Utilidades: a veces no hay más remedio.

Las clases de utilidades son esas clases que aglutinan una serie de métodos que no terminan de encajar en ninguna otra clase. Suelen ser consideradas como un “bad smell”, ya que no terminan de encajar con la realidad de la programación orientada a objetos.

Existen numerosas opiniones en su contra, como por ejemplo esta, donde hay muchos enlaces a otras opiniones. Lo cierto es que a veces parecen imprescindibles para salir rápidamente de los problemas, y en mi opinión, son una especie de crédito al banco de la deuda técnica que nos permite continuar usando un lenguaje orientada a objetos.

Sea como fuere, si tienes que usar clases de utilidades, tienes que tener en cuenta que deben cumplir estas condiciones (espero no haber olvidado nada…):

  1. Deben ser clases finales, para que nadie las pueda heredar.
  2. Deben tener un constructor privado, para que no puedan ser instanciadas.
  3. Su constructor debe lanzar un UnsupportedOperationExcepcion, por si alguien, haciendo uso de reflexión, decide hacer público el constructor (mal!!!)
  4. Sus métodos deben ser estáticos, para que puedan ser usados sin necesidad de instanciar la clase.
  5. Y también deben ser estáticos sus atributos.
  6. ¿Algo más? No sé si me ha olvidado algo…

En este tutorial vamos a hacer un test que se encargue de testear estas condiciones… Si nunca has usado la introspección… ¿imaginas cómo lo podrías hacer?

3. Sonarqube y la manía de cuantificar todo

Como ya he indicado en el apartado de advertencia, testear que una clase de utilidades tiene esas características, no aporta casi nada, y si lo aporta, es a una relación de coste muy elevada para el rendimiento obtenido…

Pero a los clientes, que no suelen ser tan expertos como nosotros en el mundo del desarrollo, para que nos permitan hacer TDD o al menos algunos test y no rechisten mucho a la hora de asumir su coste, les hemos tenido que “vender la moto” de lo bueno que es el testing. Y como la gente que maneja pasta de los presupuestos no es tonta, nos habrán pedido alguna evidencia objetiva de lo bueno que es tener test y cuántos tests hay en un proyecto y cuantos no hay en otro. Aquí entra en juego SonarQube.

SonarQube, entre otros aspectos, usa la cobertura de test unitarios para dar una puntuación de la deuda técnica, o lo que el cliente entiende: lo bueno o malo que es su producto. Y si enseñamos una clase estática, SonarQube provocará una conversación de este tipo:

  • Cliente: en esta clase tienes un 0% de cobertura de test.
  • Programador: ya, es que es una clase estática que sólo tiene constantes, no hace falta probarla.
  • Cliente: sí, lo que tú quieras, pero la cobertura de test tú módulo está al 80% mientras que la de otro está al 95%… no está por encima del 90% como hemos firmado
  • Programador: vale, pero entiende que este caso…
  • Cliente: no, no, hemos firmado un acuerdo por el que todos los tests tiene que estar por encima del 90% de cobertura… no es mi problema.
  • Programador: mmm pero es que esto no es agilismo…
  • Cliente: yo tampoco seré ágil a la hora de ordenar el pago de tu trabajo de consultoría…

Bueno, tranquilo :) es sólo una dramatización para justificar la barbaridad en contra del agilismo que voy a perpetrar a continuación, y no es otra que satisfacer al cliente !A TODA COSTA!

4. La implementación

El objetivo que me he marcado ha sido crear una clase abstracta que pueda ser extendida por otras clases de test, y que incluya los test de las condiciones que hemos enumerado en el apartado 2 de clase de utilidad.

Si haces las cosas bien, por cada clase que tengas en tu código, deberías tener otra clase que incluya sus test unitarios (si consideras que tu “unidad” es una clase – así debería ser si respetas un poco SOLID). Así, cuando tengas la clase de utilidad “UtilClass.java”, deberías tener en tu apartado de test una clase llamada “UtilClassTest.java”. O al menos eso dice la teoría.

El resultado lo puedes consultar en un GitHub que he creado para este proyecto: https://github.com/4lberto/testUtilityClasses. Podrás encontrar tanto la clase como ejemplos de test con todas las casuísticas.

La clase abstracta que nos permite testear las condiciones de una clase de utilidades es la siguiente:

public abstract class AbstractUtilityBaseTester<T> {

	@SuppressWarnings("unchecked")
	@Test
	public void shouldTestPrivateConstructor() {
		Constructor<T> constructor;
		Class<T> persistentClass = null;
		try {
			persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
					.getActualTypeArguments()[0];

			checkFinalClass(persistentClass);

			constructor = checkConstructor(persistentClass);

			checkMethodsAreStatic(persistentClass);
			checkFieldsAreStatic(persistentClass);
			checkInstanciation(constructor, persistentClass);
		} catch (SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException
				| InvocationTargetException e) {
			Assert.assertEquals(
					"The cause of the inner exception must be UnsupportedOperationException when trying to instanciate the class "
							+ persistentClass.getName() + e.getClass().getName(),
					UnsupportedOperationException.class.getName(), e.getCause().getClass().getName());
		}
	}

	private void checkFinalClass(final Class<T> persistentClass) {
		Assert.assertTrue("The class " + persistentClass.getName() + " must be final",
				Modifier.isFinal(persistentClass.getModifiers()));
	}

	private Constructor<T> checkConstructor(final Class<T> persistentClass) {
		Constructor<T> constructor;
		constructor = (Constructor<T>) persistentClass.getDeclaredConstructors()[0];
		Assert.assertTrue("The constructor of the class " + persistentClass.getName() + ", must be private",
				Modifier.isPrivate(constructor.getModifiers()));
		constructor.setAccessible(true);
		return constructor;
	}

	private void checkInstanciation(final Constructor<T> constructor, final Class<T> persistentClass)
			throws InstantiationException, IllegalAccessException, InvocationTargetException {
		final T instance = constructor.newInstance();
		Assert.assertTrue("No excepction is thrown when instanciating " + persistentClass.getName()
				+ " a UnsupportedOperationException should be thrown", false);
	}

	private void checkMethodsAreStatic(final Class<T> persistentClass) {
		final Method[] methods = persistentClass.getDeclaredMethods();
		for (int i = 0; i < methods.length; i++) {
			Assert.assertTrue(
					"Method " + methods[i].getName() + " of the class " + persistentClass.getName()
							+ " is NOT STATIC. All methods must be static",
					Modifier.isStatic(methods[i].getModifiers()));
		}
	}

	private void checkFieldsAreStatic(final Class<T> persistentClass) {
		final Field[] fields = persistentClass.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			Assert.assertTrue(
					"Field " + fields[i].getName() + " of the class " + persistentClass.getName()
							+ " is NOT STATIC. All methods must be static",
					Modifier.isStatic(fields[i].getModifiers()));
		}
	}

}

Su uso no puede ser más sencillo: si tenemos que testear la clase TypicalCorrectUtilityClass.java con el siguiente contenido:

public final class TypicalCorrectUtilityClass {

  	public static final float PI = 3.14f;

  	private TypicalCorrectUtilityClass() {
  		throw new UnsupportedOperationException("Not instanciable class!");
  	}

  	public static int convertToNumber(final String numberString) {
  		int number;
  		switch (numberString) {
  		case "uno":
  			number = 1;
  			break;
  		case "dos":
  			number = 2;
  			break;
  		default:
  			number = -1;
  			break;
  		}
  		return number;
  	}
}

Simplemente deberemos crear una clase de test haciendo uso de los genéricos para indicar la clase de utilidad:

public class TypicalCorrectUtilityClassTest
    extends AbstractUtilityBaseTester<TypicalCorrectUtilityClass> {
    ...
}

¡Qué fácil! Luego dentro de la clase ya se pueden lanzar otros test que comprueben el contenido, pero ya de por sí, al haber heredado de la clase AbstractUtilityBaseTester indicando la clase que se va a testear, se lanza el testeo de todos los puntos que debe cumplir una clase de utilidades

5. Los detalles

Vamos a ver los detalles del código que resultan de interés de la clase AbstractUtilityBaseTester:

5.1. Usando genéricos

Como lo que vamos a comprobar no es específico de ninguna clase en particular, hemos decidido utilizar genéricos para parametrizar la clase a probar. Así, mediante T le indicamos que cuando se realiza una extensión o implementación, se expresará sobre qué clase se va a proceder.

public abstract class AbstractUtilityBaseTester<T> {

El resto de código está condicionado por este genérico T. Cuando veamos T en realidad debemos ver “una clase”.

5.2. Adivinando la clase en tiempo de ejecución.

Como usamos genéricos, para sacar la clase debemos hacer una operación un poco complicada y especial. Es el precio que hay que pagar en Java por haber incorporado los genéricos. La verdad es que no es nada sencillo de entender, pero puedes ir mirando cosas como el type erasure para que entiendas la “ñapa” que tuvieron que hacer a la hora de compilar los genéricos, y por qué se debe determinar en tiempo de ejecución las clases.

Entre tú y yo… esto lo he sacado de stackoverflow.

Class<T> persistentClass = null;
  try {
  	persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
  	.getActualTypeArguments()[0];

Una vez que ya sabemos qué clase tenemos que chequear, que será la indicada en T, ¡podemos ponernos manos a la masa con la introspección y la reflexión!

5.3. ¿Es la clase final?

Muy sencillo. Además lo he separado en método privado, como a Uncle Bob le gusta :)

private void checkFinalClass(final Class<T> persistentClass) {
	Assert.assertTrue("The class " + persistentClass.getName() + " must be final",
			Modifier.isFinal(persistentClass.getModifiers()));
}

Simplemente usamos el paquete de reflection de java, concretamente a java.lang.reflect.Modifier y su método isFinal, que nos va a decir si el resultado del método getModifiers de la clase es final o no. Lo introducimos en un Assert de JUnit con su correspondiente mensaje explicativo.

5.4. ¿Es el constructor privado?

Ahora simplemente tenemos que preguntarle a la clase por su constructor. Esperemos que sólo tenga uno ^_^ (también lo podríamos haber metido en un check: hazme un pull request y lo incluyo :P)

private Constructor<T> checkConstructor(final Class<T> persistentClass) {
		Constructor<T> constructor;
		constructor = (Constructor<T>) persistentClass.getDeclaredConstructors()[0];
		Assert.assertTrue("The constructor of the class " + persistentClass.getName() + ", must be private",
				Modifier.isPrivate(constructor.getModifiers()));
		constructor.setAccessible(true);
		return constructor;
	}

El constructor también parametrizado con la clase T. Se sacan los constructores declarados con getDeclaredConstructors(). ¡Ojo!, que si usamos la función getConstructors nos devuelve también los constructores de las clases padres… Con declared, tanto para constructores como para otros elementos, indica que queremos los de la propia clase, nada de los heredados.

De igual modo, con Modifier.isPrivate comprobamos si los modifiers del constructor indica si es privado o no, y se aplica el Assert correspondiente.

Ahora viene una cosa interesante… tomamos el constructor y lo convertimos en ¡público! Con esto vamos a ser capaces de acceder a su interior en el test unitario, cargándonos por el camino la encapsulación… ¿Ves como es posible saltarse los “private” que pensabas que protegían tu código?. Veremos más delante para qué lo queremos…

5.5. ¿Son los métodos y atributos estáticos?

Al ser una clase no instanciable, todos los métodos y atributos no pueden residir en un objeto sino en la propia clase, por lo que deben ser estáticos. Se comprueba de forma muy similar los métodos y los atributos: con nuestro amigo Modifier.is…:

private void checkMethodsAreStatic(final Class<T> persistentClass) {
  		final Method[] methods = persistentClass.getDeclaredMethods();
  		for (int i = 0; i < methods.length; i++) {
  			Assert.assertTrue(
  					"Method " + methods[i].getName() + " of the class " + persistentClass.getName()
  							+ " is NOT STATIC. All methods must be static",
  					Modifier.isStatic(methods[i].getModifiers()));
  		}
  	}

  	private void checkFieldsAreStatic(final Class<T> persistentClass) {
  		final Field[] fields = persistentClass.getDeclaredFields();
  		for (int i = 0; i < fields.length; i++) {
  			Assert.assertTrue(
  					"Field " + fields[i].getName() + " of the class " + persistentClass.getName()
  							+ " is NOT STATIC. All methods must be static",
  					Modifier.isStatic(fields[i].getModifiers()));
  		}
  	}

Simplemente se recogen los métodos y atributos declarados en un vector y se recorren uno por uno, aplicando Modifiers.isStatic sobre cada elemento. En el momento que uno no lo sea, nos saltará el assert con el mensaje que permite encontrar exactamente el atributo o método que no cumple la condicion. Recuerda que los test deben informar exactamente de dónde está el error para que pueda ser subsanado de la forma más rápida posible.

5.6. ¿Lanza una excepción al ser instanciado?

Esto ya es una sobreprotección frente al private del constructor, y también un convenio que se suele utilizar por si alguien, como hemos visto, cambia en tiempo de ejecución la visibilidad del constructor: se debe devolver un UnsupportedOperationException.

Debemos recordar en este punto, que cuando se ha comprobado si el constructor era privado, después de la comprobación, se ha cambiado la visibilidad a public mediante:

constructor.setAccessible(true);

Entonces, ya podemos hacer una instancia de nuestra clase y hacer que la ejecución pase por el interior del constructor. Si está vacío o tiene algún código, se ejecutará, y eso es algo que no se quiere. Para evitarlo se lanzará una excepción con el aviso (¡esto no se puede cambiar por reflexión! – al menos que yo sepa jeje).

private void checkInstanciation(final Constructor<T> constructor, final Class<T> persistentClass)
    throws InstantiationException, IllegalAccessException, InvocationTargetException {
  final T instance = constructor.newInstance();
  Assert.assertTrue("No excepction is thrown when instanciating " + persistentClass.getName()
      + " a UnsupportedOperationException should be thrown", false);
}

Simplemente llamamos al newInstance del constructor modificado a public y esperamos que salte o no una excepción. Si no salta es que ha podido hacerlo y que dentro del constructor no se está lanzando nada, por lo que lanzamos un assert con fallo y un mensaje descriptivo.

En el caso de que se lance una excepcion, debemos comprobar que es la excepción que se lanza por convenio: UnsupportedOperationException.

Assert.assertEquals(
					"The cause of the inner exception must be UnsupportedOperationException when trying to instanciate the class "
							+ persistentClass.getName() + e.getClass().getName(),
					UnsupportedOperationException.class.getName(), e.getCause().getClass().getName());

Como la excepción irá dentro de una excepción que actúa de wrapper, se toma la causa y se comprueba de qué clase se trata para hacer el assert.

Y poco más que comentar… es solamente una clase de pocas líneas. Puedes bajarte un proyecto de maven para java +1.7 desde el GitHub que he hecho para el proyecto:https://github.com/4lberto/testUtilityClasses. ¡Úsala como te de la gana!

6. Conclusiones

Hemos visto cómo usar la introspección y reflexión en Java para hacer un poco de “magia” y testear los atributos y modificadores de clases de utilidades, aumentando la cobertura de código hasta niveles poco recomendables en el mundo del agilismo, pero sí compatibles con el ego de un perfeccionista :). Te recomiendo que profundices un poco en el tema de la reflexión en Java porque a veces puede ser de gran utilidad: Java Trail: reflection.

Datos estructurados y web semántica

$
0
0

Lo que se dice en la web tiene un significado y poco a poco empieza a interpretase de forma automática. Debajo subyace la web semántica.

Índice de contenidos


1. Introducción

No hace tanto tiempo que cada palabra en la web tenía el mismo valor para un motor de búsqueda, cuyos algoritmos indexaban la web en busca de enlaces referenciados a su vez por otras webs. No hace tanto tiempo, que ese enlace era tan valioso como el número de páginas que lo referenciaran y su reputación. No importaba si alrededor de ese enlace se decía que el servicio que prestaba tal empresa era horrible o buenísimo. Sólo se miraba cualidades cuantitativas y mesurables mediante una ponderación. Respondía a un algoritmo que otorgaba una función de peso. Y ahí empezó el principio del fin del altruismo en la red.

Y es que en el momento en que el todopoderoso Google permitió conocer la existencia del algoritmo que otorgaba una puntuación a cada página, el PageRank, se mercantilizó la web. Y lo que hasta ese momento se compartía o se recomendaba sinceramente mediante un enlace, de repente, adquirió un valor, y con el vinieron los que con él querían comerciar. Aparecieron nuevos oficios como los especialistas en SEO y SEM, que no dejaban de especular sobre los límites de un algoritmo, que constantemente se tenía que corregir para mantener la neutralidad de los resultados del buscador, y aguantar los envites de ordas de usuarios en aras de alterar dichos resultados en su beneficio.

Pero decidir si una página web es buena en términos humanos, ¿es un problema computable?. Ay, amigo, no me hace falta releer los escritos de Gödel para saber que algo tan subjetivo no lo es. Pero ¿importa? La web está llena de opiniones subjetivas acerca de algo. Nuestros algoritmos sólo tienen que leer la subjetividad que en la web se expresa en forma de epítetos, reviews y opiniones ex profeso. Creo que a estas alturas de la película nadie duda de que ciertas opiniones pesan en la calidad reputacional de un site.

¿Y cómo separar las opiniones legítimas de las opiniones fabricadas?. Una buena pregunta a la que ahora sólo puedo especular.


2. Datos estructurados

Pero nosotros podemos ayudar al buscador marcando y estructurando los datos para que Google les otorgue un significado especial.

Por ejemplo, mi colega Alberto Moratilla escribió una review de un libro, como hace tantas veces, en este caso de “Patterns of Enterpise Application Architecture” de Martin Fowler. Si hacemos una búsqueda en google de su artículo, nos encontramos con:

entrada sin rating

Mientras que hay otra entrada del buscador que tiene el siguiente aspecto

entrada con rating

Hay diferencias evidentes. Por un lado aparece un ranking, y un número de votos. Ya simplemente por eso, los datos parecen más serios. En algunos casos a esa información estructurada se puede aportar ciertos datos de importancia, por ejemplo, una foto. O si el producto es local, si se trata de un evento, como una obra de teatro, dónde se representa, y desde qué fecha y hasta cuando.

Invito al lector a buscar el título de su película favorita en el buscador y verá que los primeros resultados tienen un formato especial respecto a los demás. Incluso que a la derecha aparecen una serie de datos especiales en forma de ficha, que son la suma de esos datos estructurados provenientes de distintas fuentes.


3. Formatos soportados

Google nos indica en su página introductoria a los datos estructurados que maneja tres posibles formatos:

  • Microdatos
  • RDFa
  • JSON-LD

Aunque nos deja clara su preferencia por JSON-LD. Vamos a ver qué pinta tienen.


3.1. Microdatos

Este es probablemente el formato más antiguo. Es una forma especial de escribir el HTML y tiene su propio estándar dentro del W3C. A continuación pongo cómo sería la recomendación de un restaurante:

<div itemscope itemtype="http://schema.org/Review">
  <div itemprop="itemReviewed" itemscope itemtype="http://schema.org/Restaurant">
    <img itemprop="image" src="foto-del-restaurante.jpg" alt="Restaurante L'Abbraccio"/>
    <span itemprop="name">Restaurante italiano</span>
  </div>
  <span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">
    <span itemprop="ratingValue">4</span>
  </span> stars -
  <b>"<span itemprop="name">Un buen restaurante italiano.</span>" </b>
  <span itemprop="author" itemscope itemtype="http://schema.org/Person">
    <span itemprop="name">Carlos Martínez</span>
  </span>
  <span itemprop="reviewBody">La comida es muy buena y la atención inmejorable.</span>
  <div itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="Revista Gastronómica">
  </div>
</div>

3.2. RDFa

El mismo ejemplo del restaurante en RDFa sería:

<div vocab="http://schema.org/" typeof="Review">
  <div property="itemReviewed" typeof="Restaurant">
    <img property="image" src="foto-del-restaurante.jpg" alt="Restaurante L'Abbraccio"/>
    <span property="name">Restaurante italiano</span>
  </div>
  <span property="reviewRating" typeof="http://schema.org/Rating">
    <span property="ratingValue">4</span>
  </span> stars -
  <b>"<span property="name">Un buen restaurante italiano.</span>" </b>
  <span property="author" typeof="http://schema.org/Person">
    <span property="name">Carlos Martínez</span>
  </span>
  <span property="reviewBody">La comida es muy buena y la atención inmejorable.</span>
  <div property="publisher" typeof="Organization">
    <meta property="name" content="Revista Gastronómica">
  </div>
</div>

3.3. JSON-LD

Este formato es el preferido por Google. Como su nombre indica, conforma la información en formato llamado JSON for Linking Data. Un formato ligero, que usa JSON, lo que permite extraer este bloque de la página y consumirlo fácilmente. A mi me parece la forma ideal, porque separamos la estructura de la página web, del contenido semántico que queremos transmitir.

De esta forma, el mismo ejemplo con JSON-LD sería:

<script type="application/ld+json">
{
  "@context": "http://schema.org/",
  "@type": "Review",
  "itemReviewed": {
    "@type": "Restaurant",
    "image": "http://www.example.com/foto-del-restaurant.jpg",
    "name": "Restaurante L'Abbraccio"
  },
  "reviewRating": {
    "@type": "Rating",
    "ratingValue": "4"
  },
  "name": "Un buen restaurante italiano.",
  "author": {
    "@type": "Person",
    "name": "Carlos Martínez"
  },
  "reviewBody": "La comida es muy buena y la atención inmejorable.",
  "publisher": {
    "@type": "Organization",
    "name": "Revista Gastronómica"
  }
}
</script>

4. Ontologías

Esto de la web semántica no se lo ha inventado Google, si no que se ha aprovechado de todo el estudio de las ontologías existente. Así que trabajaremos con entidades como libros, eventos, recetas de cocina, series de televisión y cosas similares. Se hace evidente que necesitamos un diccionario que defina qué características debe tener cada una de esas entidades, cuales son obligatorias, y cuales opcionales.

Aunque hay muchos, el más famoso, y el recomendado por Google es Schema.org que cuenta con un elevado número de entidades (más de las categoríad que maneja actualmente el omnipresente buscador)

Por ejemplo, la definición de las propiedades de un libro viene dada por http://schema.org/Book. Como veréis el número de propiedades es muy elevado. En la propia página, abajo, vienen ejemplos para usarlo con microdatos, RDFa o con JSON-LD


5. Herramientas

Pero si hemos dicho que el conjunto de entidades que maneja Schema.org es mayor que el que maneja Google, ¿cómo sabremos si nuestros datos estructurados son válidos para el buscador? De momento, Google nos informa que tipos de datos son compatibles con el marcado de datos estructurados.

tipos_de_datos

Y además nos da ayuda con otras herramientas:

  • Testing-tool: una herramienta de validación de JSON-LD
  • Markup-helper: una herramienta para construir datos estructurados, donde seleccionas el tipo, y luego le indicas una URL. Se carga la página y vas seleccionando elementos. Por ejemplo, le indicas que vas a reseñar un libro, y a continuación la URL de la review. Se carga la página, y vas marcando los distintos elementos del libro: la imagen, el autor, el título, quien el es autor de la review, cual es su valoración, etc…
markup-helper

Con todo esto tenemos fácil generar los datos estructurados que necesitemos en una página web.


6. Datos estructurados en emails

Las páginas web no son las únicas que manejan datos estructurados. Muchos clientes de correo, hacen uso extensivo de ellos. GMail los usa de forma tan natural, que seguramente ni te has dado cuenta. Por ejemplo, cada vez que recibes una invitación de una reunión, o una confirmación de una reserva de vuelo u hotel, o la confirmación del pedido del mercadona. Si ves el HTML original del correo, verás que lleva incrustado los datos estructurados

En el siguiente enlace nos cuentan como añadir acciones a GMail o Inbox para aumentar la participación. Por ejemplo, con acciones sobre eventos:

acciones_eventos_gmail

El caso es que no siempre sale bien a la primera, y hay que recurrir al viejo empirismo, y probar por uno mismo el resultado. Eso sí, necesitaremos un sistema para enviar HTML con un script en JSON-LD embebido. Hay que tener en cuenta, que casi todos los clientes web, escapan el contenido que se envía por cuestiones de sobreescribir estilos y por seguridad, quitando ciertas etiquetas. Y una de las que se suelen escapar es la etiqueta de <script>. Así que hay que garantizar que el cliente que lo envía no la quita, y que el servidor del destinatario, tampoco. De ahí, la parte empírica y los ensayos sobre este punto.


7. Conclusiones

Se ve que esto de los datos estructurados podría evolucionar más. Y que podemos ayudar a la semántica, en cosas concretas como reviews, productos, eventos, y alguna entidad más. Pero que la inversión de tiempo y esfuerzo no permite etiquetar cada cosa que se escriba para la red. Lo que lleva a la cuestión que subyace al uso de los datos estructurados, y no es ni más ni menos, que la semántica de nuestros párrafos debería poder extraerse del propio lenguaje natural escrito.

Sirva este artículo, como ejemplo, de lo que se puede hacer para aquellas cosas concretas que nos interesa destacar.


8. Referencias y enlaces

El manifiesto “The Twelve-Factor App”

$
0
0

Vamos a conocer un manifiesto que contiene los puntos fundamentales que debería cumplir el desarrollo de una aplicación preparada para ser distribuida como un servicio.

1. Introducción

No cabe duda de que en el mundo del desarrollo el cambio es una constante en prácticamente todos los aspectos. Y uno de ellos es el de la distribución de aplicaciones: hemos pasado de aplicaciones que se ejecutaban en ordenadores locales a aplicaciones distribuidas en servidores Web ejecutados en ordenadores conectados a Internet; posteriormente aparecieron los servicios de hosting, que evolucionaron a la nube, que nos ofrece diferentes modelos bastante alejados ya del clásico ordenador en el que nos teníamos que montar todo, desde el sistema operativo, drivers, servidor de aplicaciones, conexiones a Internet, firewalls…

Actualmente, en el mundo del cloud computing podemos clasificar los servicios en alguna de estas tres capas incrementales:

  • IaaS (Infraestructura as a Service): se refiere a la posibilidad de hacer uso de ordenadores en la nube, bien físicos o máquinas virtuales. No dista mucho del modelo clásico de tener el control total de un ordenador donde tenemos que montar todo (aunque hay imágenes prefabricadas). Además incluyen otros elementos como firewalls, balanceadores, almacenamientos… Ejemplos: Amazon EC2, Microsoft Azure o muchos distribuidores menos conocidos: Gigas, OVH, Arsys…
  • PaaS (Platform as a Service): una capa por encima del IaaS: nos dan por ejemplo el acceso al servidor de aplicaciones, de modo que nos abstrae del sistema operativo y del resto de componentes, que ya nos dan mantenidos. De este modo nos olvidamos de mantener las máquinas, sistemas operativos y nos podemos centrar en la aplicación. Por ejemplo tenemos Amazon Lambda, Heroku o Google App Engine, donde simplemente subimos el fichero .war con nuestra aplicación. El resto de cosas ya están solucionadas.
  • SaaS (Software as a Service): lo que hacemos es comprar el uso de una aplicación bajo demanda: Office 360, Google Drive, Flickr, Gmail, Facebook… Nos olvidamos completamente de la instalación y del mantenimiento.

La llegada de la nube (cloud computing) y de estos nuevos modelos, ha provocado un cambio en la forma de desarrollar y mantener aplicaciones, o mejor dicho en su ciclo de vida. Bajo mi punto de vista estos son algunos de los puntos claves:

  • Ahora tenemos acceso a poder utilizar un gran número de máquinas.
  • La popularización de Internet hace que sea factible llegar a un gran público (viral en ocasiones), de modo que podemos utilizar el acceso a un número enorme de máquinas para cubrir las altas demandas. ¡Más vale que estemos listos para escalar!
  • La necesidad de automatizar todo. Cuando había un par de servidores era factible hacer operaciones a mano, pero con cientos es imposible. Así surge DevOps…
  • La alta competencia exige alta adaptación: las aplicaciones deben estar vivas para responder a los cambios de requisitos, por lo que deben poder desplegarse rápidamente.
  • La aparición de nuevos modelos fruto del nuevo esquema: ya no nos valen las máquinas con sus sistemas operativos, ahora se tiende a hacer containers aislados, microservicios, funciones como servicios (FaaS)…

Conclusión: como desarrolladores también tenemos que prestar mucha atención no sólo a los requisitos funcionales de la aplicación sino también al entorno en el que se va a ejecutar.

2. El Manifiesto “Twelve-Factor Apps”

Ahora también nos ha dado por la “serverless architecture”… y leyendo sobre ello en la página de Martin Fowler (http://martinfowler.com/articles/serverless.html) me encontré varias veces con la mención a un manifiesto sobre el desarrollo de aplicaciones SaaS que pienso que ilustra muy bien los “12 mandamientos” que deberíamos cumplir en el desarrollo de aplicaciones en la nube.

Se trata de un manifiesto algo viejo ya (de 2012), creado por desarrolladores experimentados en la creación y despliegue de aplicaciones en Heroku, y que recoge los 12 puntos claves que ellos consideran que se deberían cumplir para el desarrollo de aplicaciones en la nube. En realidad, en el manifiest indican aplicaciones SaaS, es decir, que se desarrolla para desplegar en PaaS, pero los consejos que dan yo los aplicaría a cualquier desarrollo de aplicación que vaya a ser distribuida en Internet hoy en día. Me parecen consejos generales que es fundamental cumplir.

El manifiesto es de libre acceso y está traducido a diferentes idiomas, entre ellos el castellano: http://12factor.net/es/ así que me limitaré a hacer un breve resumen.

2.1. Objetivos del manifiesto

En la introducción se indica que el objetivo es lograr:
  • Usar configuraciones automatizables y explícitas, nada manual.
  • Dependencias claras con el entorno en el que se ejecutan para máxima compatibilidad.
  • Tener en cuenta que la aplicación será desplegada en la nube.
  • Despliegue continuo, por tanto requiere coordinación de entornos (test-uat-pre-pro…).
  • Crear aplicaciones con la escalabilidad en la mente.

2.2. Los 12 factores

Como he indicado antes, el manifiesto es corto de leer, así que te recomiendo que acudas a la fuente original (http://12factor.net/es/, aunque mejor en inglés – http://12factor.net/). Haré aquí un rápido repaso (quizá con mi opinión) por cada uno de los puntos y animarte así a que profundices en estos mandamientos o factores:

  1. Código Base: el código debe estar en repositorios y es desde ahí donde se harán los despliegues a los entornos. Puede haber varios repositorios si la aplicación es compleja, pero no se puede repetir código entre repositorios (hacer un split común).

  2. Dependencias: todas las dependencias de la aplicación deben ser explícitas y existir un sistema automático que las instale si no existen. Por ejemplo, un proyecto Java bien montado con Maven o con Gradle no presupone que hay librerías instaladas en la máquina: las descarga si no las tiene. Pienso que de igual manera se tiene que aplicar al sistema operativo: apt-get para instalar curl…

  3. Configuraciones: el código no puede tener configuraciones, sino que deben ser separadas en otros recursos dependientes del entorno. Así, el código debe hacer referencia a las variables de configuración pero no a los valores. Esto permite instalar el mismo código en diferentes entornos. Ejemplos: URL de servicios, claves de bases de datos, variables de entorno…

  4. Backing services: son recursos conectables a la aplicación, independientemente de si son locales o de terceros. Si la aplicacion necesita una base de datos, será tratada como un recurso independiente, con su URL y su instalación, que deben ser proporcionados a la aplicación. Si un servidor de bases de datos proporciona 2 esquemas diferentes, serán tratados como si estuvieran en servidores diferentes (aunque luego sus URL y credenciales coincidan).

  5. Construir, distribuir y ejecutar: son las 3 etapas que se deben pasar para transformar el código fuente en un producto utilizable. Deben ser tratadas de forma independiente y con un control de las versiones que se van distribuyendo acorde a un sistema preestablecido. Nada de darle al botón build del eclipse sobre el servidor de producción :-).

  6. Procesos sin estado (stateless): la aplicación se ejecuta en el destino como un proceso (o varios) en la máquina anfitriona pero la información que existe en su espacio de memoria sólo tiene lo necesario para hacer las transacciones que lleva a cabo en ese momento, no para atender a transacciones futuras: puede reiniciarse la máquina, aparecer otro proceso… La información que sea necesario almacenar para el futuro se hará en un Backing Service como Redis, Memcache… Olvídate del “Sticky Session”… esto es ¡escalable!

  7. Asignacion de puertos: el código no puede considerar a priori la asignación de los puertos. Simplemente sabe que es un proceso que escucha en un puerto arbitrario. Será la configuración la que establezca los puertos de cada componente. Esto es similar a lo que sucede con los microservicios y/o con Docker: en una misma máquina hay diferentes procesos escuchando en puertos configurados, y que incluso unos procesos actúan como Backing services de otros.

  8. Concurrencia: las aplicaciones deben estar desarrolladas teniendo en mente la concurrencia, bien de hilos o bien de procesos. La razón principal es la naturaleza distribuida y la capacidad para escalar levantando nuevas máquinas. Los procesos nunca deberían ser de tipo demonio, sino delegar en el sistema operativo y los mecanismos que dispone.

  9. Disponibilidad: las aplicaciones deben ser capaces de iniciar sus procesos rápidamente y de respoder de forma controlada a la finalización, aunque esta sea inesperada. Cuando hablamos de escalado, nos referimos al inicio o parada en caliente de nuevas máquinas o al traslado a diferentes máquinas de los procesos.

  10. Paridad en el desarrollo y producción: se refiere a tener los diferentes entornos (des-pre como mínimo) lo más similares posibles, tanto de versiones de código desplegado, como de entornos y servicios. Esto se hace con despliegues continuos, lo que implica automatizar los despliegues lo máximo posible, que el personal de desarrollo sea mucho más consciente del entorno de producción y que incluso se compartan modos de trabajo entre entornos aunque no sea lo más evidente a primera vista: puppet, chef, ansible…

  11. Historiales: o más conocidos como “Logs”. Las aplicaciones no se preocupan del direccionamiento y almacenamiento de sus datos de logs. Para eso existen sistemas específicos en cada entorno. Incluso actualmente es posible disponer de sistema de procesamiento en tiempo real como Splunk o ELK, que permiten estar al tanto de una manera más sencilla del comportamiento de la aplicación.

  12. Administrador de procesos: además de los procesos propios de la ejecución de la aplicación, existirán procesos de tareas de administración y mantenimiento que suelen ejecutarse una única vez. Estos procesos, aunque puedan parecer secundarios, se ejecutarán con igual importancia que el resto de los procesos de la aplicación. Además, se recomienda el uso de consolas REPL si el entorno dispone de ellas (en Java 9 habrá una).

Parece que tiene sentido, ¿no? Quizá sea una buena idea que evalúes cuántos puntos de este dodecálogo estás cumpliendo :).

3. Conclusiones

Las nuevas opciones para la distribución de las aplicaciones en Internet afectan a la forma de desarrollarlas y en general a su ciclo de vida: la necesidad de adaptarse a la demanda, tanto en número como nuevas capacidades, y hacerlo con una demora cada vez menor, nos fuerza a adoptar nuevos enfoques.

En este tutorial hemos hecho un repaso al manifiesto “Twelve-Factor app” para el desarrollo de aplicaciones en la nube, un dodecálogo cargado de experiencia y sentido común que es muy conveniente tener en cuenta en nuestros desarrollos.

Diseño de formularios usables

$
0
0

El formulario es quizás el elemento más importante de un website. Existe mucha documentación sobre cuál es la mejor manera de diseñarlos, de manera que sean efectivos y logren un alto ratio de conversión. En este post he fusionado todas las indicaciones sobre formularios que hay dispersas tanto en libros como en internet. Espero que os sirva de ayuda.

Índice de contenidos


1. Las reglas de oro

  • Elige los campos correctos:

    Por regla general, a nadie le gusta rellenar formularios, de modo que cuanto más sencillo sea, mayor ratio de conversión obtendrás. Esto significa, entre otras cosas, que un formulario debe tener un máximo de 7 campos y solicitar la información mínima necesaria en ese momento.

    Debemos tener en cuenta que al rellenar el formulario, el usuario debe dar información personal, lo que supone que debe confiar en el sitio. Piensa en un formulario de registro que solicita tu número de teléfono. ¿Lo rellenarías? ¿Es realmente necesario solicitar esa información en este punto?

  • Simple y claro:

    Debe quedar claro lo que el usuario debe introducir en cada campo, no utilices textos que lleven a error. Por ejemplo en Asana, una aplicación para gestión de tareas y proyectos empresariales, al registrarte pide que introduzcas un nombre y no queda claro si se refiere al tuyo o al de tu empresa, o si podrás modificarlo más adelante en caso de que te equivoques.

    Campo de formulario confuso
  • Cuida el diseño:

    Este punto es extensible al resto de elementos del sitio y debe mantener una coherencia entre ellos. El 48% de la gente considera que el diseño es el factor principal que decide la credibilidad del negocio¹, y en función de si les agrada o no, tardarán entre 4 y 6 segundos en decidir si continúan navegando. Piensa que la web de tu empresa es, en muchos casos, el primer contacto que tiene un usuario con tu marca.

  • Mantén el engagement:

    Una vez completado y enviado el formulario, agradece o felicita al usuario e intenta mostrar un mensaje que le invite a permanecer en tu sitio ( “Ya has dado tu primer paso”).

    Mensaje de agradecimiento

2. Construyendo el formulario

Los campos del formulario deben mostrarse en una única columna para facilitar su legibilidad.

Formulario dos columnas

Cada label debe situarse sobre su input, no al lado, y debes tener cuidado para que no haya la misma distancia entre su input y el que tenga encima, especialmente en formularios grandes. Debe quedar claro a qué input corresponde.

Label a un lado

Prescinde de los asteriscos para indicar campos obligatorios, ya que incita al usuario a saltar los opcionales. Es preferible señalar éstos últimos de manera suti

Campo opcional

Evita utilizar los inputs como labels.

Inputs como labels

Indica qué información será pública y cuál no. También se puede indicar si podrá modificar ese campo en el futuro o si no podrá hacerlo.

Mensaje información privada

Es importante que los mensajes de error sean explicativos y amigables. Si su aspecto es demasiado rudo o su texto no explica lo que ha sucedido y cómo el usuario debe solucionarlo, es muy probable que se sienta frustrado y no continue rellenándolo. Piensa que el 88% de los usuarios no vuelven a visitar una web tras una mala experiencia². Además, el mensaje de error debe aparecer cuando el usuario abandone el campo, no mientras aún lo está editando.

Mensaje de error explicativo

No ocultes los mensajes de ayuda en un tooltip, es mejor que los muestres. También es conveniente indicar el formato a introducir, por ejemplo en las fechas.

Formulario con tooltip
Información de formato

Intenta sustituir el clásico mensaje de “Enviar” en el botón de Submit por algo más descriptivo como “Únete ahora”. Si hay varios botones y quieres resaltar alguno, no utilices el color como clave diferenciadora única. Emplea negrita, diferentes tamaños o cualquier otra técnica.

Mensaje submit personalizado

En caso de que necesites recoger mucha información y por tanto, insertar un formulario con muchos campos, es recomendable utilizar formularios escalonados (Stepped Forms), que dividen el proceso en pequeñas secciones. Esto además evita, en algunos casos, mostrar campos innecesarios en función de elecciones que el usuarios haya tomado en pasos anteriores. También puedes incluir una barra de progreso para que el usuario sepa en qué punto se encuentra y cuánto falta para terminar.

Barra de progreso

A cada paso del formulario, es recomendable mostrar un mensaje sobre las ventajas de rellenarlo. Debemos recordar al usuario por qué lo hace (ej.: “Al finalizar el formulario obtendrás 1 mes del servicio gratis”).

En caso de no poder dividir el formulario, puedes agrupar los campos por categorías (Datos personales, información de la cuenta, etc.).

walgreens-registration-forms-comparison-from-nn-group

3. Conclusiones

El formulario es el punto de contacto entre la empresa y el usuario, y debemos hacer todo lo que esté en nuestra mano para que lo rellene con éxito, ya que es donde se suelen perder la gran mayoría de conversiones. Hemos visto que para conseguirlo hace falta más que una estética agradable, y que siguiendo una serie de pautas UI, podemos guiar a los usuarios con un mínimo esfuerzo.


4. Referencias

Cifrado de información sensible con Ansible Vault

$
0
0

En este tutorial comprobaremos como subir información sensible de forma segura a nuestro sistema de control de versiones con ansible-vault.

Índice de contenidos


1. Introducción

Cuando llevas un tiempo trabajando con Ansible, te das cuenta de que en tus ficheros de propiedades tienes un montón de información sensible, como contraseñas de la base de datos, o información sensible de la aplicación que estás desarrollando. Podrías pensar en subir esa información sensible al control de versiones, pero entonces perderías todas las ventajas que esto conlleva. Para solventar esto, desde la versión 1.5 Ansible nos provee de Ansible Vault, que nos permite subir nuestros ficheros de forma cifrada.

Esta herramienta ya viene instalada con Ansible por defecto, así que vamos a comprobar qué podemos hacer con ella 😀


2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro Retina 15′ (2.5 Ghz Intel Core I7, 16GB DDR3).
  • Sistema Operativo: Mac OS El Capitán 10.11.2
  • Ansible 2.1.0.0

3. Ansible Vault

Para proteger la información sensible, utilizamos ansible-vault para ser capaces de versionar los archivos que contienen las claves de la configuración sin comprometer su seguridad al estar expuestos a un sistema de control de versiones.


3.1. Cifrar

Terminal
$ ansible-vault encrypt

Este comando pide una contraseña, qué es la que se usará a la hora de querer descifrar el archivo.

IMPORTANTE: Tener en cuenta que todas las tareas que se ejecuten juntas deben compartir la misma contraseña. Es decir, si ciframos varios ficheros de propiedades que pueden ser usados de forma simultánea en el mismo playbook, se deben cifrar sus ficheros de propiedades con la misma clave.


3.2. Descifrar

Terminal
$ ansible-vault decrypt

Este comando descifra el fichero, dejando la información tal y como estaba antes de cifrarlo.

Yo no recomiendo usar este comando para editar un fichero previamente cifrado y subido al control de versiones porque al volver a subir los cambios se te puede olvidar volver a cifrarlo de nuevo, y eso te obligaría a cambiar otra vez todas las credenciales que estén almacenadas en tu fichero de propiedades.

RECUERDA: Hay que subir el fichero cifrado al repositorio. No subir nunca el fichero sin cifrar.


3.3. Editar

Terminal
$ ansible-vault edit

Este comando te permite editar el fichero con tu editor del terminal por defecto (Vim en mi caso), y cuando guardas el fichero, vuelve a dejarlo cifrado. Este es el comando que yo te recomiendo para editar, como su propio nombre indica, porque no se te va a olvidar nunca volver a cifrar el archivo.


3.4. Ver por consola

Terminal
$ ansible-vault view

Este comando nos mostrará el contenido del fichero cifrado. Ideal si solo quieres recordar el contenido, y no quieres arriesgarte a editarlo por error 😀


3.5. Cambiar la clave de cifrado

Terminal
$ ansible-vault rekey

Es bien conocido por todos que debemos de ir renovando nuestras contraseñas con frecuencia. Para cambiar la contraseña que utilizamos para cifrar nuestros archivos, podemos usar el comando anterior.


4 Ejecución de Ansible con propiedades cifradas

Una vez tenemos nuestros ficheros cifrados, ahora nos falta saber como cambia nuestro comando de ejecución de Ansible, y cómo podemos indicarle la clave que hemos elegido para cifrar el fichero.

Podemos indicarle esta contraseña de dos maneras: mediante un fichero que contenga la propiedad o escribiéndola directamente después de ejecutar el comando.


4.1. Ejecutar Ansible con las claves cifradas sin introducir manualmente la contraseña

Terminal
$ ansible-playbook -i inventory playbook.yml -vvvv --vault-password-file ~/.vault_pass.txt

En este caso, el fichero se llamaría .vault_pass.txt y estaría en nuestra Home. Ese fichero solo contendría una línea con nuestra contraseña.

Como este fichero podemos ponerlo en cualquier lugar, tenemos que asegurarnos de NO versionar este fichero, ya que si no, todos nuestros esfuerzos por subir el fichero cifrado serían en vano.

¡IMPORTANTE!: Hay que establecer los permisos del fichero para que solo sea accesible por el usuario que se va a encargar de ejecutar Ansible, para mayor seguridad.


4.2. Ejecutar Ansible con las claves cifradas introduciendo las contraseñas

Terminal
$ ansible-playbook -i inventory playbook.yml -vvvv --ask-vault-pass

Tras ejecutar el comando, verás como en el prompt de la terminal pone “Vault password:” donde tendrás que escribir la contraseña para que pueda ejecutarse el playbook.


6. Conclusiones

Como hemos podido apreciar, es muy fácil subir información sensible a nuestro control de versiones gracias a Ansible Vault.


7. Referencias

WebComponents: un vistazo rápido

$
0
0

Acercamiento al mundo de los WebComponents, qué son y cómo funcionan, por qué deberíamos empezar a usarlos, y si ya están listos para emplearlos en producción.

Índice de contenidos


1. ¿Por qué deberíamos usar WebComponents?

Hasta que aparecieron los WebComponents las páginas webs definían su paleta de componentes que seguían la guía de estilo corporativa, definiendo por un lado su estructura HTML, por otro funciones JavaScript, y por otro estilos que les otorgaban el look and feel que permitía que se integraran visualmente en la web con coherencia.

Pensemos así, en, por ejemplo la página web de reserva de hoteles, donde tiene componentes propios para su negocio, como por ejemplo, un rango de fechas: desde – hasta. O un banco, donde tiene campos de CCC, IBAN o un campo compuesto por número de tarjeta de crédito, títular, y fecha de caducidad. Son susceptibles de convertirse en componentes.

Que bien nos vendrían los siguientes componentes:

<date-range>
<input-iban>
<input-credit-card type="visa">

Pues para eso están los WebComponents.

Y aquí es donde choca con las modas. Ahora está muy de moda usar frameworks MVC en el lado del cliente, y muchos de ellos tienen resuelto el problema de cómo crear componentes. El problema es que los componentes creados así, se casan con la tecnología. Y los componentes creados con AngularJS en su versión 1, pues dependen de que la web esté usando esta versión. Por tanto, yo prefiero utilizar estos frameworks MVC para orquestar todo lo demás, pero utilizando WebComponents estándar, que sé que me van a funcionar independientemente del framework de turno utilizado. Me van a funcionar, incluso en páginas web clásicas, que no son “Single Page Applications”.

En este sentido, ¿no es mejor para cualquier empresa tener su propia paleta de componentes definidos de forma estándar con WebComponents?

Yo sólo le puedo ver ventajas.

Vivimos un momento de espectacular florecimiento de diversas tecnologías front, dando lugar a un ecosistema muy volátil y cambiante, dirigido en muchos casos por las modas, y éstas nunca deben imponerse al sentido común. Los WebComponents son un estándar que desacopla su uso de la tecnología empleada para construirlos.


2. ¿Qué son y cómo funcionan los WebComponents?

Son cuatro los mecanismos nuevos que se juntan para llevar esta revolución al HTML. Por un lado, tenemos nuevos elementos HTML personalizados, llamados Custom Elements y que nos permitirán definir nuevas etiquetas HTML a nuestro antojo. Por otro lado, disponemos de la definición de plantillas, templates que vamos a usar para definir cómo serán internamente esos elementos en base a otras piezas más pequeñas, otros elementos HTML previos, o elementos personalizados, pudiendo de esta forma, hacer plantillas complejas. Otra funcionalidad de que disponemos es el Shadow DOM que es como el DOM interno del elemento que estamos creando, y que está oculto para ser manipulado desde fuera. Esto es genial, porque los CSSs de fuera del componente no sobrescribirán los estilos que definamos dentro del mismo, al estar esté DOM oculto al resto de la página. Y luego la cuarta funcionalidad, los HTML imports, que se invocan en la cabecera para realizar la carga del WebComponent, y que esté disponible en nuestra página para poder hacer uso del elemento personalizado.

Así que todo se resume a la combinación de estas cuatro definiciones:

Los HTML Templates ya están incluidos dentro de la especificación de HTML5, mientras que los demás, su especificación está en modo borrador por el W3C. Pero se espera que no sufran ya demasiadas modificaciones. De hecho, la mayoría de los navegadores aceptan como un estándar de facto la especificación actual, con algunos matices.

Como pasa casi siempre, menos con JavaScript, los navegadores van por delante de la definición del estándar.

Pero esos matices, nos obligan en algunos navegadores, sobre todo en los más antiguos, a usar polyfills. Esto es, una serie de complementos en forma de código, para que los navegadores que no soportan el estándar de forma nativa, con estos complementos, sí puedan. Y aquí es donde aparecen frameworks de desarrollo de WebComponentes como X-Tag, Polymer, Bosonic y SkateJS. El más famoso de todos es Polymer, que detrás tiene a Google y una gran comunidad de desarrolladores. X-Tag no se queda atrás, ya que es Mozilla quien lo soporta.


3. WebComponents en producción

La primera pregunta que se hará alguien que se esté planteando usar WebComponents es: “¿y esto puedo usarlo en entornos productivos sin problema?”. Lo cierto es que sí. Ya lleva bastante tiempo funcionando y son multitud de webs las que incorporan en su código Componentes Web. Hay catálogos de componentes listos para ser usados: y podemos encontrar desde Data Grids avanzados a mapas de geoposicionamiento, o gráficos estadísticos. Todo al alcance de una simple etiqueta personalizada.

Con esta versatilidad, ¿qué compañía no preferiría tener su propio juego de componentes? Donde cada componente define su propio aspecto, su comportamiento, y sus validaciones. Listo para ser utilizado, y que los desarrolladores sólo tengan que usar la etiqueta personalizada, sin preocuparse de efectos laterales e indeseados.

En un siguiente artículo, reseñaré como crear un componente web de ejemplo.


Enlaces y referencias

Monit como watchdog configurado con Ansible

$
0
0

En este tutorial veremos Monit como herramienta para monitorizar el estado de los servicios, así como tomar las acciones pertinentes en caso de que no esté como esperábamos.

Índice de contenidos


1. Introducción

En este tutorial nos introduciremos en el apasionante mundo de la monitorización de aplicaciones, para lo que utilizaremos Monit como watchdog. Un watchdog en informática es una herramienta que registra uno (o varios) servicios, que deben estar periódicamente enviándole información para asegurar que están disponibles. Entendemos por servicio desde nuestro servidor web, desde Apache o Nginx hasta nuestras propias aplicaciones web.

He de comentar que si queremos un sistema de monitorización más avanzado de nuestras aplicaciones, deberíamos de ver la serie de tutoriales de mi compañero David donde habla de la monitorización de logs con Elasticsearch, Logstash y Kibana. Este tipo de monitorización es complementaria y específica de nuestra aplicación, mientras que Monit actúa como watchdog de gran cantidad de servicios (de mensajes, de ficheros, de bases de datos, FTP…)

Como suele ser costumbre en mis tutoriales, probaremos esta herramienta de monitorización en una máquina virtual creada con la combinación de Vagrant y Virtual Box y aprovisionada con Ansible.

El objetivo de este tutorial es enseñarnos como funciona Monit, monitorizando un servidor web, concretamente un Nginx. Para ello, crearemos una máquina virtual donde instalaremos Monit y Nginx, y comprobaremos como cuando paramos el servicio, este vuelve a levantarse sin nuestra intervención gracias a Monit.


2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro Retina 15′ (2.5 Ghz Intel Core I7, 16GB DDR3).
  • Sistema Operativo: Mac OS El Capitán 10.11.16
  • Vagrant 1.8.1
  • Virtual Box 5.0.14
  • Ansible 2.1.0.0
  • Monit 5.6
  • Nginx 1.4.1

3. Instalación de Vagrant, Virtual Box y Ansible

Como mencionábamos en la introducción, antes de ponernos manos a la obra, necesitamos tener Vagrant, Virtual Box y Ansible instalado. En este tutorial explico cómo se instalan estas herramientas. A partir de aquí suponemos que ya tienes esas herramientas instaladas y funcionando.


4. Creación de la máquina virtual

La creación de la máquina virtual es muy sencilla. Basta con irnos al directorio dónde queramos crear la máquina virtual y configurar el Vagrantfile que usará Vagrant para crearnos nuestra máquina virtual. Nuestro Vagrantfile tendrá la siguiente estructura:

Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
    config.vm.box = "ubuntu/trusty64"

    config.vm.network :forwarded_port, host:  2222, guest: 22, id: "ssh"
    config.vm.network :forwarded_port, host:  8888, guest: 80, id: "nginx"

    config.vm.network :private_network, ip: "192.168.33.25"

    config.vm.define "monit" do |monit|
        monit.vm.hostname = "monit"

        monit.vm.provision "ansible" do |ansible|
          ansible.verbose = 'vvv'
          ansible.playbook = "ansible/watchdog_nginx.yml"
        end
    end
end

En esta configuración, como siempre elegimos la “box” de Vagrant a partir de la que se va a crear la máquina virtual. Luego, se configuran los puertos para realizar la conexión con la máquina, de forma que cuando en nuestra máquina anfitrión pongamos la url localhost:8888 estaremos accediendo al puerto 80 de la máquina virtual (192.168.33.25:80).

Por último, tenemos la configuración de Ansible en la que decimos que después de crear la máquina ejecute el playbook watchdog_nginx.yml, y que la salida sea muy verbosa. Esto quiere decir que nada más crear la máquina virtual va a ejecutar los roles que, como decíamos en la introducción, se encargarán de instalarnos Nginx y Monit.


5. Creación de los roles de Ansible

A continuación nos queda crear los roles de Ansible que vamos a ejecutar cuando se cree la máquina. Para ello dentro del directorio dónde tenemos nuestro Vagrantfile, y siendo fieles a la propiedad que hemos establecido en el mismo dónde indicábamos el playbook (ansible.playbook = “ansible/watchdog_nginx.yml”), creamos el directorio “ansible” dónde guardaremos todos nuestros archivos de Ansible.


5.1. Playbook

El playbook que vamos a ejecutar tiene el siguiente formato:

ansible/watchdog_nginx.yml
---
# file: watchdog_nginx.yml

- hosts: monit
  become: yes
  gather_facts: no
  roles:
      - nginx
      - monit

Aquí le decimos que en el host Monit, nos ejecute como usuario privilegiado los roles de Nginx y de Monit. El nombre Monit se lo pusimos como hostname en la configuración de Vagrant.

Si recordáis los dos elementos imprescindibles para aprovisionar con Ansible son: Qué quiero ejecutar (esa información viene dada en el playbook) y dónde quiero ejecutarlo (información que viene dada en el inventory). Pero si nosotros no hemos definido un inventory, ¿cómo sabe la máquina que dónde tiene que ejecutar el playbook es la máquina que acabamos de crear? Esto se sabe debido a que Vagrant crea un fichero inventory auto-generado que está en la ruta .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory que es relativa al directorio dónde tenemos creado nuestro Vagrantfile.


5.2. Rol de Nginx

Este rol solo instala Nginx en la máquina y le añade una directiva para que el servidor web actúe como proxy inverso de la aplicación objetivo, en este caso del propio Monit.

Las tareas que se ejecutan en este rol son:

ansible/roles/nginx/tasks/main.yml
# file: /roles/nginx/tasks/main.yml

- name: install nginx
  apt:
    name:  nginx
    state:  present
    update_cache: yes

- name: create nginx proxy configuration
  copy:
    src: "virtualhost-conf"
    dest: "/etc/nginx/sites-available/virtualhost.conf"
  notify: restart nginx

- name: create symlink to custom nginx configuration
  file:
   src: /etc/nginx/sites-available/virtualhost.conf
   dest: /etc/nginx/sites-enabled/virtualhost.conf
   state: link
  notify: restart nginx

- name: remove default configuration
  file:
    path: /etc/nginx/{{ item }}
    state: absent
  with_items:
      - sites-available/default
      - sites-enabled/default
  notify: restart nginx

Como vemos en el rol, usamos el módulo copy por lo que en su parámetro src esperará encontrar el fichero virtualhost-conf en el directorio ansible/roles/nginx/files. También tenemos una cláusula notify, que espera que haya un fichero main.yml en el directorio ansible/roles/nginx/handlers que contenga una tarea que tenga el nombre específico “restart nginx”, que se encarga de hacer reiniciar el servicio. Vamos a crearlos 😉

ansible/roles/nginx/files/virtualhost-conf
server {
    listen 80 default_server;
    server_name test;

    location /monit {
        rewrite ^/monit/(.*) /$1 break;
        proxy_ignore_client_abort on;
        proxy_pass   http://127.0.0.1:2812;
        proxy_redirect  http://127.0.0.1:2812 /monit;
    }
}
ansible/roles/nginx/handlers/main.yml
# file: /roles/nginx/handlers/main.yml

- name: restart nginx
  service:
      name: nginx
      state: restarted

Con esto ya tendríamos el rol de Nginx creado. ¡Vamos con el de Monit!


5.3. Rol de Monit

El rol de Monit se encarga de instalar Monit y de copiar un fichero de configuración que usará para saber que servicios tiene que monitorizar, definirá las reglas de como hacerlo, y avisará en función del estado del servicio, en este caso por email usando el servidor de correo de Google.

Las tareas que tiene este rol son:

ansible/roles/monit/tasks/main.yml
---
# file: /roles/monit/tasks/main.yml

- name: install monit
  apt:
      name: monit
      state: installed
      update_cache: yes

# Is located in /etc/monit/monitrc because monit expected that the properties files are there when execute as a service
- name: copy monit configuration
  template:
      src: "monitrc"
      dest: "/etc/monit/monitrc"
      mode: "0700"
      force: yes
  notify: restart monit

- name: ensure monit is monit enabled
  service:
    name: monit
    state: started

Vemos como este rol también tiene la cláusula notify, por lo que esperamos tener dentro del directorio ansible/roles/monit/handlers un fichero llamado main.yml con una tarea de nombre “restart monit”

A diferencia del rol de Nginx que usaba el módulo copy vemos que en la segunda tarea usamos el módulo template. La diferencia principal es que espera encontrar el fichero monitrc dentro del directorio ansibleroles/monit/templates y que este fichero actúa como plantilla donde puedes añadir variables.

¡Vamos a crear estos ficheros!

ansible/roles/monit/handlers/main.yml
---
# file: roles/monit/handlers/main.yml

- name: restart monit
  service:
    name: monit
    state: restarted

Y ahora la plantilla de la configuración de Monit

ansible/roles/monit/templates/monitrc
## Start Monit in the background (run as a daemon):
set daemon {{ monit_check_services_intervals }}   # check services at 1-minute intervals
    with start delay {{ monit_check_services_intervals }}   # initial delay needed for applications that restart when reboot the instance

## Set syslog logging with the 'daemon' facility. If the FACILITY option is
## omitted, Monit will use 'user' facility by default. If you want to log to
## a standalone log file instead, specify the full path to the log file
#
# set logfile syslog facility log_daemon
set logfile /var/log/monit.log

## Set the location of the Monit id file which stores the unique id for the
## Monit instance. The id is generated and stored on first Monit start. By
## default the file is placed in $HOME/.monit.id.
#
# set idfile /var/.monit.id
set idfile /var/lib/monit/id

## Set the location of the Monit state file which saves monitoring states
## on each cycle. By default the file is placed in $HOME/.Monit.state. If
## the state file is stored on a persistent filesystem, Monit will recover
## the monitoring state across reboots. If it is on temporary filesystem, the
## state will be lost on reboot which may be convenient in some situations.
#
set statefile /var/lib/monit/state

# Set mail server witch sends mail
set mailserver smtp.gmail.com port 587
    username "{{ monit_sender_account_email }}" password "{{ monit_sender_account_password }}"
    using tlsv1
    with timeout 30 seconds

# Set recipients who receive the alerts
{% for recipient in monit_alert_recipients %}
set alert {{ recipient }}
{% endfor %}

# Set mail alert format
set mail-format {
     from: monit@server.com
     subject: [ $SERVICE ] $EVENT - $DATE
     message: This is an $ACTION: $DESCRIPTION [$SERVICE] }

# Access to the Web Service
set httpd port 2812 and
    use address localhost  # only accept connection from localhost
    allow localhost        # allow localhost to connect to the server and
    allow admin:monit      # require user 'admin' with password 'monit'

{% for process in monit_process_to_check %}
check process {{ process.name }} with pidfile {{ process.pid }}
   start program = "{{ process.start_command }}" with timeout {{ process.timeout }} seconds
   stop program = "{{ process.stop_command }}" with timeout {{ process.timeout }} seconds
   {% for term in process.terms %}
   {{ term }}
   {% endfor %}

{% endfor %}

Como vemos, este fichero viene comentado (los comentarios son el texto que está después de #) explicando para que sirve cada directiva parte del fichero. De todas formas vamos a hacer un repaso rápido de por qué hemos usado esas directivas.

  • set daemon [seconds] with start delay [seconds]: Indica que Monit sea ejecutado en background, además de darle un determinado timeout antes de empezar, y también se establece el tiempo en segundos en el que el watchdog comprueba la disponibilidad de los servicios que monitoriza.
  • set logfile [logfile]: indica dónde van a estar los logs de Monit.
  • set idfile [idfile]: indica dónde se va a encontrar un id único para la instancia del Monit.
  • set statefile [statefile]: establece el fichero dónde se guardan los estados que guarda Monit de los servicios monitorizados en cada ciclo.
  • set mailserver [mail-server] port [port-number] username [username] password [pwd] using tlsv1 with timeout 30 seconds: Indica el servicio de mailing que se va a utilizar. En nuestro caso, usamos el servicio de mensajería de Google, para lo cual damos las credenciales de una cuenta de gmail que va a ser usada con para ENVIAR el mail.

    Si te preocupa el hecho de poner información sensible, como la contraseña de un correo en un fichero de Ansible, puedes mirar este tutorial sobre como cifrar información sensible con ansible-vault.

  • set alert [mail-to-alert]: Esta directiva indica los correos electrónicos que van a RECIBIR la alerta. Si no especificas nada más a la derecha de la directiva, se enviará un correo electrónico por evento diferente, aunque también es posible enviar correos solo para eventos específicos. SI quieres saber más sobre los eventos de Monit, consulta el siguiente enlace. Para este ejemplo no queremos ningún filtro por evento así que lo dejamos como está.
  • set mail-format [format]: Aquí especificamos el contenido del mensaje del mail
  • set httpd port [port-number] and use address [monit-host] allow [monit-host] allow [monit-access-user]:[monit-access-password]: Con esta propiedad permitimos el acceso al servicio web desde el puerto 2812 (puerto por defecto de Monit). El motivo por el cual hemos montado un Nginx que haga de proxy inverso es porque Monit viene con una aplicación web para ver la monitorización. Es normal añadir una capa de seguridad entre nuestra aplicación e Internet, y no exponer directamente los puertos de nuestra aplicación hacia afuera, dejando solo disponibles los puertos 80 y 443.
  • check process [unique name] [PIDFILE [path] | MATCHING [regex]: Esta directiva nos permite monitorizar un servicio en base a unas reglas específicas y realizar una acción respecto al servicio monitorizado en caso de que esté en un estado que no sea el esperado (reiniciar el servicio, ejecutar un script…).

    En nuestro caso comprobamos que el puerto 80 está disponible, y por lo tanto Nginx levantado. En caso de que nos de una respuesta negativa en dos ciclos de Monit (cada ciclo viene definido por el intervalo que pusimos en la primera directiva) se intenta arrancar el servicio.

    Como vemos en la plantilla, le indicamos como se para y como se arranca el servicio, así como el pid (el id del proceso) que estamos monitorizando. Por último, iteramos los términos que implican las acciones que va a realizar dada una precondición.

Como vemos, las plantillas de Ansible son un mecanismo muy potente que usa por debajo el sistema de plantillas de jinja2 para permitirnos iterar y poder ajustarnos a las necesidades específicas de cada servicio.

¿Dónde están definidas las variables de la plantilla? Como norma general, y dado que las variables de Ansible pueden estar definidas en varios sitios, yo os recomiendo que todas las variables que usa un rol estén definidas en el directorio defaults dentro del mismo rol. Por lo que nuestras variables estarían en la ruta: ansible/roles/monit/defaults/main.yml

ansible/roles/monit/defaults/main.yml
---
# file: roles/monit/defaults/main.yml

monit_check_services_intervals: "5"

monit_process_to_check:
    - name: nginx
      pid: /var/run/nginx.pid
      start_command: /etc/init.d/nginx start
      stop_command: /etc/init.d/nginx stop
      timeout: 10
      terms:
          - if failed port 80 for 2 cycles then restart

monit_sender_account_email: "email@gmail.com"
monit_sender_account_password: "emailpass"

monit_alert_recipients:
    - email@gmail.com

Como comprobaréis el valor de las propiedades monit_sender_account_email, monit_sender_account_password y monit_alert_recipients debe ser definido por vosotros en cada caso o no funcionará. En mi caso usaré dos correos electrónicos para que uno envíe los mensajes de Monit y otro los reciba.


6. Comprobación

Ahora que ya tenemos nuestra configuración de la máquina virtual levantada, y el aprovisionamiento que va a realizar Ansible preparado, en el directorio dónde tenemos el Vagrantfile ejecutamos el comando:

Terminal
vagrant up

Y esperamos a que suceda la magia 😀

Una vez termine el playbook, deberíamos de ser capaces de ver en el navegador con la ruta localhost:8888 la página por defecto de instalación de Nginx.

Default image from Nginx

Si ahora vamos a la ruta localhost:8888/monit tras introducir las credenciales de acceso (hemos puesto de usuario admin y de contraseña monit) accederemos a la aplicación web que nos ofrece Monit y veremos como el estado del servicio de Nginx es satisfactorio.

Monit Interface

Ahora vamos a hacer una pequeña prueba en la que paramos manualmente el servicio, y esperamos que Monit intente levantar el servicio de forma automática sin nuestra intervención. Para ello vamos a acceder a la máquina virtual por ssh y vamos a parar el servicio de Nginx, ejecutando los siguientes comandos desde el directorio en el que está nuestro Vagrantfile:

Terminal
vagrant ssh
sudo service nginx stop

Ten en cuenta que como hemos parado el servicio del Nginx, la aplicación web que veíamos tiene que dejar de ser accesible. Es decir, que si recargas la página en el instante después de haber parado el servicio ya no verás la interfaz web. Entonces, ¿Cómo sabemos si el servicio Nginx se ha levantado o sigue caído sin hacer F5 cada poco tiempo? ¿Recuerdas las notificaciones por mail que tenemos que recibir cuando se produzca un evento? Pues vamos a ver como en el correo nos llega un mensaje de que el servicio está caído, y como al cabo de un corto periodo el servicio vuelve a estar operativo.

Mail Events

Comprobamos que Nginx vuelve a estar operativo volviendo a localhost:8888

Default image from Nfinx after restart

Y como justo después de parar el servicio y esperar a que Monit lo restaure no hemos realizado ningún comando:

Auto restart from Nginx


7. Conclusión

Tener la seguridad de que tus aplicaciones son capaces de intentar recuperar su estado ideal de forma automática no tiene precio cuando estás en producción y cada instante que tu aplicación no está en el aire son potenciales clientes que estás perdiendo.

Monit te ofrece una gran potencia con una configuración muy sencilla y es rápido y fácil de instalar, por lo que si estás empezando a monitorizar tus aplicaciones, sin duda es una buena forma de comenzar. 😀

El código completo (también el rol de Nginx y de Monit que no se han mostrado) están en mi repositorio de GitHub, de forma que solo hay que bajárselo y seguir las instrucciones desde el punto 6.


8. Referencias


Gestión del estado de las dependencias NPM

$
0
0

En este tutorial vamos a ver una forma muy cómoda para saber si tus aplicaciones JavaScript con dependencias NPM están al día.

Índice de contenidos


1. Entorno

Este tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil Mac Book Pro 15″ (2,3 Ghz Intel Core i7, 16 GB DDR3)
  • Sistema Operativo: Mac OS X El Capitan

2. Introducción

Actualmente cuando trabajas en proyectos con JavaScript te darás cuenta de la cantidad ingente de dependencias que tiene tu proyecto tanto de producción como de desarrollo, y claro, cuando una de ellas se queda sin soporte, vienen los problemas.

Casi seguro que a estas alturas tu gestor de dependencias es NPM, así que tengo buenas noticias, ya que existe una herramienta online que te informa de la versión actual de todas las dependencias NPM que tiene tu proyecto, cuál es la última versión estable de esa dependencia y si esa versión que estás utilizando ha dejado de tener soporte.

Además te ofrece un pequeño “badget”, es decir, una imagen que puedes poner en cualquier sitio web y que te informa en todo momento del estado de tus dependencias.

La herramienta en cuestión no es que tenga un nombre muy descriptivo, se llama David y esta es su URL.


3. Vamos al lío

Si visitamos la página web, lo primero que nos llama la atención es que la herramienta se integra con GitHub, así que si no tienes una cuenta de Github (que ya me extrañaría) es el momento de hacerte una.

El proceso es tan sencillo como hacer click en el enlace “Sign in” con el icono de GitHub.

Nos registramos con nuestras credenciales de GitHub y aceptamos los permisos solicitados.

Una vez registrados podemos acceder a la información de las dependencias de nuestros proyectos en GitHub simplemente accediendo con una URL donde el prefijo es la propia web de David, a lo que le sigue tu usuario de GitHub y el repositorio que quieras consultar. Ejemplo: https://david-dm/raguilera82/poc-cli y si todo es correcto verás una tabla con una información parecida a esta.

Como ves te divide las dependencias entre las que son de código de producción y las que sólo se utilizan para procesos de desarrollo.

Te lista todas las dependencias y, de cada una de ellas, te informa de la versión que tienes actualmente (required), la versión siguiente más estable (stable), la última versión aunque no sea estable y un código de color (status) donde verde significa que esa dependencia está al día, amarillo que no está en la última versión pero la versión que tienes sigue teniendo soporte y rojo que significa que la versión ya no tiene soporte, y deberías actualizarla cuanto antes.

Además, para no tener que estar pendiente de consultar esta tabla, la herramienta te ofrece un “badge” que puedes utilizar en el README del proyecto o en cualquier página HTML.

Para obtenerlo, simplemente pulsa sobre el icono que se muestra en la imagen y se abrirá una ventana modal con los distintos enlaces, en función del tipo de imagen que prefieras.


4. Conclusiones

Una herramienta muy sencilla pero que nos ofrece información muy importante sobre el estado de las dependencias NPM que estamos utilizando. Ya no hay excusas del tipo “es que no me enteré que la versión X de la dependencia Y ha dejado de tener soporte y la he liado parda en producción” 😉

Cualquier duda o sugerencia en la zona de comentarios.

Interactuando con esos enrevesados humanos

$
0
0

Nosotros, los humanos, somos bastante buenos sacando el significado por contexto. Los ordenadores son terribles, hacen exactamente lo que les decimos que hagan. La diversión llega cuando les damos información incorrecta para formatear números.

Éste artículo es una traducción al castellano de la entrada original publicada, en inglés, por Dr. Heinz Kabutz en su número 236 del JavaSpecialists newsletter. Puedes consultar el texto original en Javaspecialists’ Newsletter #240: Interfacing with Messy Humans

Este artículo se publica traducido en adictos, con permiso del autor, por David Gómez García, (@dgomezg)consultor tecnológico en Autentia, colaborador de JavaSpecialists e instructor certificado para impartir los cursos de JavaSpecialists.

Interactuando con esos enrevesados humanos

Bienvenidos a la edición número 240 de The Javatm Specialists’ Newsletter, escrita desde Ljubljana, Slovenia. He impartido aquí mí Extreme Concurrency & performance course for Java 8 para Epilog, una pequeña compañía de ingeniería. Como hago siempre, pregunté a los alumnos cuánta experiencia tenían con Java. Algunos de ellos llevan programando en Java más tiempo que yo, así que estaba profundamente intimidado: ¿Cómo podría enseñarles nada nuevo?. Resultó que tuvimos unas buenísimas discusiones sobre algunos temas avanzados de Java y me satisfizo saber que me gané el sueldo :-)

La última noche, su CEO nos llevó a visitar la ciudad y nos contó la historia de Ljubljana. Sí, ese es un beneficio adicional de trabajar con empresas pequeñas: Un tour privado con el CEO. ¿Sabíais que la rueda más antigua de Europa se descubrió en Ljubljana?. ¡Data de hace aproximadamente 5150 años! Es también la rueda de madera más antigua descubierta nunca. Buscadlo.


Interactuar con esos Locos Humanos

Es difícil programar las máquinas para que piensen como nosotros. Igual que las personas con síndrome de Asperger, se toman las cosas demasiado al pie de la letra. Tenemos que medir nuestras palabras con cuidado. Puede que piensen que realmente querías hacer “sudo rm -rf /“.

En 1984, mi padre compró un ZX Spectrum. Quería utilizarlo para hacer cálculos con una hoja de cálculo. En cuanto la hoja de cálculo se acababa de cargar desde una cinta de audio, y tras una larga espera, empezaba a introducir sus números con impaciencia. No funcionó. Cada número tenía un signo de interrogación parpadeando a su lado. No sabían cuál podía ser el error con sus números. En determinado punto, me pidieron que echase un vistazo. Como ya había hecho algo de programación en BASIC, se me ocurrió sugerir que utilizasen el punto decimal como separador decimal, en lugar de la coma. Eso solucionó el problema y a los 13 años, fue la primera vez que me encontré este problema. Pero no la última.

Oficialmente, en Sudáfrica, ciento veintitrés mil cuatrocientos cincuenta y seis Rands sudafricanos con setenta y ocho céntimos se escribe con el siguiente formato: “R123 456,78”. El punto decimal es una coma y el separador de miles es un espacio. Pero no cualquier espacio: un espacio indivisible (U+00A0). Casi nadie utiliza el formato oficial. Escribimos “R123,456.78”, igual que en Estados unidos o Reino Unido. Esto es así para banca y compras por internet, documentos gubernamentales, contratos, etc…. Pero podrías encontrarte cualquiera de estos formatos “R123456.78”, “R123456,78”, “R123 456.78”, “R123 456,78” o “R123,456.78”. Nuestros cerebros humanos de lógica difusa ni siquiera perciben que hay diferencias. Lo analizamos con lo que más sentido nos parece que tiene.

Dado que tenemos tantas opciones, es responsabilidad de cada persona elegir cuál es el que prefiere ver. Personalmente me gusta “R123 456.78”, pero a veces lo escribo como “R123’456.78”. Nunca utilizo la coma como separador decimal. Y tampoco lo hace ninguno de mis bancos en Internet. Mis auditores me envían los extractos financieros con un espacio como separador de miles, agradable a la vista. En sus facturas utilizan el punto como separador decimal. Incluso aunque la coma es el separador decimal en el formato oficial, casi nadie lo usa.

En la Europa continental es diferente. Aquí todo el mundo usa la coma como separador decimal. Hace unos años intenté pagar 502.46 libras esterlinas a mis impresores en Inglaterra a través de banco local por internet. Después de haber enviado el pago, recordé que había olvidado enviarles el justificante de pago. Cuando revisé la transacción comprobé que… ¡el portal de banca online había ignorado el punto!. ¡Dios mío! Afortunadamente pude cancelar rápidamente la transferencia.

Pese a llevar viviendo en Europa 10 años, sigo utilizando en_ZA como locale en mi máquina, porque tiene como formato de fecha el genial yyyy/MM/dd. No obstante, me he dado cuenta de que algunas actualizaciones de Mac OS X actualizan de manera que mis puntos decimales vuelven a verse como comas. En la “configuración avanzada” de mi máquina, tuve que personalizar mi configuración en_ZA para utilizar un formato más familiar como #,###.##. Así los números en mi aplicación vuelven a verse bien. El único peligro son esos bancos europeos por internet.

Un divertido juguete con el que he jugado últimamente es un torno Carbide3D Nomad CNC. Por supuesto, lo controlo desde Java. Preparé un pequeño programa que permitiría al torno seguir el cursor del ratón en mi pantalla y comenzar a perforar en el momento en que pulsase el botón del ratón. Es divertido ver la cabeza del torno seguir mis movimientos, como un perro obediente. La forma de interactuar con el torno CNC es a través de GCode, un antiguo lenguaje de control basado en texto para indicar qué cortar. No tan antiguo como la rueda de Ljubljana, pero casi. Conecté todo y ejecuté mi programa. La máquina tartamudeo y empezó a girar fuera de control, intentando perforar la mesa, volando a izquierda y derecha, arriba y abajo, a toda velocidad. Tiré del cable de alimentación para desenchufarlo. Por los pelos…, pero ¿qué es lo que estaba mal?.

Había preparado con cuidado todo mi GCode usando String.format("%.3f") para asegurarme de que tenía el número perfecto de puntos decimales en los comandos. Sin embargo, por error ¡había ejecutado mi código con JDK9 Early Access!. Sip, utilizar una version EA de Java con un equipo potencialmente peligroso para tallar madera no parece muy inteligente. Pero, al tiempo que jugaba con el torno CNC, estaba también revisando el código de la JDK en Java 9, y en concreto cómo se usa VarHandles en las clases atómicas y de concurrencia. Había olvidado volver a configurar mi entorno con Java 8.

Con la ayuda de Stuart Marks y Ben Evans, descubrimos que Java 9 utiliza ahora los formatos Unicode “oficiales” para los puntos decimales. Para Sudáfrica, eso significa que todos tus números decimales se convertirán automáticamente en “123 456,78” en el futuro, te guste el formato o no. Recuerda que ya había personalizado el formato en mi máquina a un “123,456.78” mucho más común. Mi error con String.format() estaba en que asumí que descartaría la información de localización. Lo mejor es especificar siempre el locale que necesitas, usando String.format(Locale.US, "%.3f", num).

Definitivamente, es un bug descartar las personalizaciones de usuario. He dado de alta el bug de Java y en menos de 24 horas, lo cerraron como “not an issue”. Lo es. Afecta a un país con 50.000.000 o 50,000,000 o 50 000 000 habitantes. Ya sé que es “sólo África” y además, “No tienen ordenadores allí” </sarcasmo>. Microsoft hizo algo parecido imponiéndonos esa configuración oficial (la que no usa nadie), pero también aceptaron las configuración de usuario. Si vives en Sudáfrica y esto te afecta, ¿quizá quieras también notificar el bug?

Para ver la regresión en Java 9, echa un vistazo a este código:

import java.text.*;
	import java.util.*;

	public class PayPrinters {
	  public static void main(String... args) throws Exception {
	    Locale en_ZA = new Locale("en", "ZA");
	    NumberFormat format = NumberFormat.getInstance(en_ZA);
	    System.out.printf(en_ZA, "%,.2f%n", 123456.78);
	    parse(format, "123 456,78"); // normal space
	    parse(format, "123 456.78"); // normal space
	    parse(format, "123\u00a0456,78"); // no-break space
	    parse(format, "123\u00a0456.78"); // no-break space
	    parse(format, "123456,78");
	    parse(format, "123456.78");
	    parse(format, "123.456,78");
	    parse(format, "123,456.78");
	  }

	  private static void parse(NumberFormat format, String number)
	      throws ParseException {
	    System.out.println("parse(\"" + number + "\") = " +
	        format.parse(number));
	  }
	}

Este es el resultado con varias versiones de Java que tengo en mi Mac OS X. El número se formatea como 123,456.78 en Java 6, 7, y 8, pero en Java 9 aparece como 123 456,78, ignorando por completo mi configuración. Utilizar un espacio indivisible es arriesgado. No lo puedes ver. Y la mayoría de la gente usará un espacio normal, en cuyo caso el número tampoco se podrá parsear.

heinz$ java -showversion PayPrinters
	java version "1.6.0_65"
	Java(TM) SE Runtime Environment (build 1.6.0_65-b14-468-11M4833)
	Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-468, mixed mode)

	123,456.78
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123456,78") = 12345678
	parse("123456.78") = 123456.78
	parse("123.456,78") = 123.456
	parse("123,456.78") = 123456.78
heinz$ java -showversion PayPrinters
	java version "1.7.0_80"
	Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
	Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)

	123,456.78
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123456,78") = 12345678
	parse("123456.78") = 123456.78
	parse("123.456,78") = 123.456
	parse("123,456.78") = 123456.78
heinz$ java -showversion PayPrinters
	java version "1.8.0_101"
	Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
	Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)

	123,456.78
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123456,78") = 12345678
	parse("123456.78") = 123456.78
	parse("123.456,78") = 123.456
	parse("123,456.78") = 123456.78
heinz$ java -showversion PayPrinters
	java version "9-ea"
	Java(TM) SE Runtime Environment (build 9-ea+134)
	Java HotSpot(TM) 64-Bit Server VM (build 9-ea+134, mixed mode)

	123 456,78
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123 456,78") = 123456.78
	parse("123 456.78") = 123456
	parse("123456,78") = 123456.78
	parse("123456.78") = 123456
	parse("123.456,78") = 123
	parse("123,456.78") = 123.456

Hay un workaround que descubrió Stuart Marks. Si arrancas la JVM con ‑Djava.locale.providers=HOST,CLDR,JRE utiliza primero tu configuración, después el Unicode oficial (CLDR) para tu locale y por último, la configuración de la JRE. En mi opinión, éste debería ser el valor por defecto para las JVMs. Aquí veis su salida en Java 9:

heinz$ java -Djava.locale.providers=HOST,CLDR,JRE \
	    -showversion PayPrinters
	java version "9-ea"
	Java(TM) SE Runtime Environment (build 9-ea+134)
	Java HotSpot(TM) 64-Bit Server VM (build 9-ea+134, mixed mode)

	123,456.78
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123 456,78") = 123
	parse("123 456.78") = 123
	parse("123456,78") = 12345678
	parse("123456.78") = 123456.78
	parse("123.456,78") = 123.456
	parse("123,456.78") = 123456.78

Gracias por leer este artículo :-) Breve y bonito, que mi vuelo de vuelta a casa está a punto de salir.

Saludos.

Heinz.

SonarLint: Integración de Sonar en IntelliJ IDEA

$
0
0
SonarLint: Integración de Sonar en IntelliJ IDEA

Índice de contenidos

1. Introducción

En la introducción del tutorial Integración de SonarQube en Eclipse se exponen las razones de la integración de nuestro entorno de desarrollo con el servidor de sonar corporativo. En esta ocasión vamos a mostrar la instalación e integración del plugin SonarLint para IntelliJ IDEA.

2. Entorno

El tutorial está escrito usando el siguiente entorno:
  • Hardware: Portátil MacBook Pro Retina 15′ (2.2 Ghz Intel Core I7, 16GB DDR3).
  • Sistema Operativo: Mac OS El Capitan
  • Entorno de desarrollo: Intellij Idea 2016.2.2
  • SonarQube 5.1.2

3. Instalación

Para instalar plugins en IntelliJ Idea, en el menú de preferencias, hay un apartado llamado Plugins, no tiene pérdida. Nos muestra los plugins actualmente activos y, en la parte inferior, nos ofrece tres opciones: instalación de plugins de JetBrains, búsqueda de plugins en los repositorios e instalar plugin desde nuestro disco local. Si le damos a Browse repositories, tendremos un cuadro de búsqueda para filtrar por nombre de plugin. SonarLint01

Escribiendo SonarLint aparecerá el plugin y una descripción sobre el mismo. En la descripción está el botón de Instalar.

SonarLint02

Tras pulsarlo, se instala el plugin y pedirá reiniciar el IDE.

SonarLint03

4. Configuración

Una vez que termine de reiniciarse, en el cuadro de búsqueda del menú de preferencias escribimos SonarLint. Con el filtro aparece una configuración general de SonarLint y otra para el proyecto. SonarLint04

En la general, vamos a agregar el servidor de sonar corporativo.

SonarLint05

Se indica el nombre que queramos, y la URL del servidor. También indicamos el tipo de autenticación, en nuestro caso, mediante usuario y password. Comprobamos que la conexión se realiza satisfactoriamente.

SonarLint06

Damos a OK y cerramos la ventana de diálogo. En SonarQube servers aparece nuestro servidor. Se pueden agregar varios servidores. En cuanto se añade un nuevo servidor, realizará una actualización de datos contra el servidor para obtener información sobre el listado de proyectos, las reglas, perfiles, etc. Posteriormente podemos actualizarlo con Update Binding.

SonarLint07

Desde SonarLint Project Settings se configura sonar para nuestro proyecto. Se activa la conexión.

SonarLint08

Seleccionamos el servidor contra el que queremos pasar el análisis de este proyecto

SonarLint09

y en SonarQube project seleccionamos el proyecto en el que estamos trabajando.

SonarLint10

5. Análisis

Ya lo tenemos configurado, solo falta lanzar en análisis de sonar. En la parte inferior tenemos el menu SonarLint con un icono rojo (junto al terminal, Version Control, etc), en el podemos configurar el scope del análisis con el fichero actual o con todos los abiertos (aún no está disponible un análisis completo del proyecto). Seleccionamos el que se desee y le damos al triángulo verde. SonarLint11

Cuando termina el análisis, tenemos los issues por cada fichero y el listado desplegable, y en el propio fichero abierto nos marca los problemas (issues). También muestra la explicación de java respecto a la vulnerabilidad.

SonarLint12

6. Ponlo a tu gusto

Los issues detectados Sor sonar dentro del código vienen con unos colores por defecto, pero dentro de preferencias, en editor -> Colors & Fonts -> SonarLint los podremos configurar como queramos.

7. Conclusiones

La instalación y configuración del plugin SonarLint es muy sencilla, y aunque el tutorial está basado en IntelliJ, el plugin está también disponible para Eclipse y Visual Studio, así que no hay excusa para no integrarlo con nuestro IDE favorito.

8. Referencias

Monitorización centralizada con M/Monit y Ansible

$
0
0

En este tutorial veremos M/Monit para monitorizar aplicaciones distribuidos en varias máquinas de forma centralizada.

Índice de contenidos


1. Introducción

Ya hemos hablado en el tutorial sobre Monit como watchdog configurado con Ansible de la monitorización de las aplicaciones con un watchdog como Monit, que era capaz de informarnos si un servicio estaba disponible, y en caso de que lo no estuviera podía ejecutar acciones de forma autónoma.

Monit nos sirve para monitorizar una máquina, pero ¿qué pasaría si nuestro sistema se compone de dos aplicaciones (A y B) que se ejecutan en dos máquinas diferentes (M1 y M2 respectivamente)? Tendríamos la monitorización de A en M1, y la monitorización de B en M2. Además, tiene la desventaja de que no podemos ver las dos cosas a la vez, y de que en cada máquina configuramos un servidor web para proteger la vista de la monitorización que suele ser útil para el equipo de desarrollo.

Siguiendo este ejemplo, lo que podríamos hacer es tener una tercera máquina (M3) donde instalaríamos M/Monit, que usaría el Monit de las máquinas M1 y M2 como clientes que envían datos a esta última máquina, por lo que el servidor web no tiene que exponer el dashboard de cada aplicación. Además, conseguimos separar la monitorización de las propias aplicaciones, por lo que cada máquina está dedicándose solo a una única cosa (M1 a gestionar la aplicación A, M2 a gestionar la aplicación B y M3 a monitorizar las aplicaciones de ambas).

Una vez entendido el ejemplo, vamos a realizar uno más sencillo para el cual solo necesitamos dos máquinas virtuales:

  • La primera máquina virtual será como en el primer tutorial de Monit: tendrá un Nginx y un Monit que se encarga de monitorizarlo y de arrancar el servicio de forma automática cuando se para.
  • La segunda máquina virtual tendrá M/Monit que recibirá los datos del Monit que está en la primera máquina virtual.

NOTA: Se recomienda encarecidamente leer el tutorial anterior ya que gran parte de los playbook puestos a continuación se explican en el mismo.

NOTA2: En este caso, no haría falta el fichero de configuración que mapea la ruta localhost:8888/monit a localhost:2812 (acceso a la interfaz gráfica de Monit) ya que es justo para eso para lo que creamos la otra máquina, pero lo dejamos para que el paso entre tutoriales sea más cómodo.


2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro Retina 15′ (2.5 Ghz Intel Core I7, 16GB DDR3).
  • Sistema Operativo: Mac OS El Capitán 10.11.16
  • Vagrant 1.8.1
  • Virtual Box 5.0.14
  • Ansible 2.1.0.0
  • Monit 5.6
  • Nginx 1.4.1

3. Instalación de Vagrant, Virtual Box y Ansible

Antes de ponernos manos a la obra, necesitamos tener Vagrant, Virtual Box y Ansible instalado. En este tutorial explico cómo se instalan estas herramientas. A partir de aquí suponemos que ya tienes esas herramientas instaladas y funcionando actualmente.


4. Creación de las máquinas virtuales

Para definir las reglas de la creación de nuestras máquinas virtuales lo haremos usando Vagrant. Para ello, en el directorio de nuestra elección crearemos el fichero Vagrantfile con la siguiente configuración:

Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
    config.vm.box = "ubuntu/trusty64"

    config.vm.define "monit" do |monit|
        monit.vm.hostname = "monit"

        monit.vm.network :forwarded_port, host:  2222, guest: 22, id: "ssh"
        monit.vm.network :forwarded_port, host:  8888, guest: 80, id: "nginx"

        monit.vm.network :private_network, ip: "192.168.33.25"
    end

    config.vm.define "mmonit" do |mmonit|
        mmonit.vm.hostname = "mmonit"

        mmonit.vm.network :forwarded_port, host:  2223, guest: 22, id: "ssh"

        mmonit.vm.network :private_network, ip: "192.168.33.26"
    end

    config.vm.provision "ansible" do |ansible|
        ansible.verbose = 'vvv'
        ansible.playbook = "ansible/watchdog_nginx.yml"
    end
end

Como se ve, definimos dos host, monit y mmonit cada uno con una ip privada diferente dentro de la misma red (para que Monit y M/Monit puedan comunicarse) y vemos como tienen redirección de puertos hacia el puerto 22 en las dos máquinas (para aprovisionarlas con Ansible) y en el 80 en la máquina de monit para el Nginx.

Por último tenemos el aprovisionamiento de cada una de las máquinas con Ansible, donde le decimos que nos ejecute el playbook watchdog_nginx.yml.


5. Creación de los roles de Ansible

A continuación nos queda crear los roles de Ansible que vamos a ejecutar cuando se cree la máquina. Para ello dentro del directorio donde tenemos nuestro Vagrantfile y, siendo fieles a la propiedad que hemos establecido en el mismo donde indicábamos el playbook (ansible.playbook = “ansible/watchdog_nginx.yml”), creamos el directorio “ansible” donde guardaremos todos nuestros archivos de Ansible.


5.1. Playbook

El playbook que vamos a ejecutar tiene el siguiente formato:

ansible/watchdog_nginx.yml
---
# file: watchdog_nginx.yml

- hosts: monit
  become: yes
  gather_facts: no
  roles:
      - nginx
      - monit

- hosts: mmonit
  become: yes
  gather_facts: no
  roles:
      - m_monit

Es básicamente igual al del tutorial anterior, salvo que le añadimos otra cláusula con el host de mmonit y le decimos que ejecute el rol m_monit.


5.2. Rol de Nginx

El rol de Nginx es exactamente igual al de el anterior tutorial, donde ya lo hemos explicado.


5.3. Rol de Monit

En cuanto al rol de monit la manera de instalarlo sigue exactamente igual que en el anterior tutorial, solo que en el fichero ansible/roles/monit/templates/monitrc se ha de añadir la configuración específica para que Monit actúe como cliente y envíe la información a M/Monit. La configuración adicional que hay que añadir es:

ansible/roles/monit/templates/monitrc
# Set the URL to be used by Monit for sending messages to M/Monit
set mmonit http://{{ monit_mmonit_user }}:{{ monit_mmonit_password }}@{{ monit_mmonit_host }}:8080/collector

Aquí vemos como lo que hacemos es especificar un endpoint al API rest de M/Monit para lo cual necesitamos las credenciales de acceso (por defecto viene con dos usuarios: monit//monit y admin/swordfish siendo el segundo administrador) y el host de M/Monit (definido previamente en el Vagrantfile).

Como hemos añadido nuevas variables (monit_mmonit_user, monit_mmonit_password y monit_mmonit_host), debemos añadirlas a nuestro fichero de variables ubicado en ansible/roles/monit/defaults/main.yml

main.yml
---
# file: roles/monit/defaults/main.yml

monit_mmonit_user: monit
monit_mmonit_password: monit
monit_mmonit_host: 192.168.33.26

monit_check_services_intervals: "5"

monit_process_to_check:
    - name: nginx
      pid: /var/run/nginx.pid
      start_command: /etc/init.d/nginx start
      stop_command: /etc/init.d/nginx stop
      timeout: 10
      terms:
          - if failed port 80 for 2 cycles then restart

monit_sender_account_email: "email@gmail.com"
monit_sender_account_password: "email-password"

monit_alert_recipients:
    - email@gmail.com

5.4. Rol de M/Monit

Por último creamos el rol de M/Monit, que va a ser el encargado de instalar y configurar M/Monit.

La instalación por defecto viene con una base de datos SQLite, de forma que si queremos tener pocos datos, como es nuestro caso, es suficiente. Si la cantidad de datos a manejar es mayor, M/Monit te ofrece la posibilidad de cambiar la base de datos a un MySQL o PostgreSQL. En este enlace os dejo información sobre como hacerlo.

Vamos a comprobar las tareas que componen este rol 😀

main.yml
---
# file: /roles/m_monit/tasks/main.yml

- name: download M/Monit
  get_url:
      url: "{{ m_monit_donwload_url }}"
      dest: "/tmp/{{ m_monit_dir_tar_gz }}"

- name: create file
  file:
      path: /opt/mmonit-3.5.1
      state: directory

# environment clause it´s necessary because of a bug with the unarchive module
- name: extract mmonit
  unarchive:
      src: "/tmp/{{ m_monit_dir_tar_gz }}"
      dest: "{{ m_monit_base_dir }}"
      copy: no
  environment:
      LANG: C
      LC_ALL: C
      LC_MESSAGES: C

- name: Add mmonit links for management version
  file:
      src: "{{ m_monit_base_dir }}/{{ m_monit_dirname }}"
      dest: "{{ m_monit_base_dir }}/mmonit"
      state: link
      force: yes

- name: Enable mmonit for management as a service
  template:
      src: mmonit_init
      dest: "/etc/init.d/mmonit"
      owner: root
      group: root
      mode: "0755"
      force: yes

- name: Remove unextracted mmonit
  file:
      path: "{{ m_monit_base_dir }}/{{ m_monit_dir_tar_gz }}"
      state: absent

- name: ensure mmonit is running and enabled as service
  service:
      name: "mmonit"
      state: started
      enabled: yes

Como vemos los pasos son autoexplicativos:

  • Primero nos descargamos en un directorio temporal.
  • Luego lo extraemos y creamos un enlace simbólico para usar Monit abstrayéndonos de la versión y que sea más sencillo el usar múltiples versiones o elegir la de nuestra elección.
  • Configuramos M/Monit para arrancarlo como servicio con un script.
  • Borramos los datos que no necesitamos y nos aseguramos de que el servicio está habilitado.

A continuación mostramos el script que hace que M/Monit actúe como servicio, que está localizado en ansible/roles/m_monit/templates/mmonit_init:

mmonit_init
#!/bin/sh

#
# Sample init script for M/Monit to be placed in /etc/init.d/ and linked to run levels
#


DESC="mmonit"
NAME=mmonit
DAEMON={{ m_monit_base_dir }}/{{ m_monit_dirname }}/bin/$NAME
SCRIPTNAME=/etc/init.d/$NAME
PIDFILE=/var/run/mmonit.pid

# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0

d_start() {
        $DAEMON -p /var/run/ || echo -en "\n already running"
}

d_stop() {
        kill -QUIT `cat $PIDFILE` || echo -en "\n not running"
}

d_reload() {
        kill -HUP `cat $PIDFILE` || echo -en "\n can't reload"
}

case "$1" in
        start)
                echo -n "Starting $DESC: $NAME"
                d_start
                echo "."
                ;;
        stop)
                echo -n "Stopping $DESC: $NAME"
                d_stop
                echo "."
                ;;
        reload)
                echo -n "Reloading $DESC configuration..."
                d_reload
                echo "."
                ;;
        restart)
                echo -n "Restarting $DESC: $NAME"
                d_stop
                sleep 5
                d_start
                echo "."
                ;;
        *)
                echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
                exit 3
                ;;
esac

exit 0

En este script lo que cambiamos indicamos como operar con el servicio de M/Monit.

Por último nos queda definir todas las variables usadas en este playbook. Eso lo hacemos en el fichero ansible/roles/m_monit/defaults/main.yml

ansible/roles/m_monit/defaults/main.yml
---
# file: roles/m_monit/defaults/main.yml

m_monit_donwload_url: "https://mmonit.com/dist/mmonit-3.5.1-linux-x64.tar.gz"

m_monit_base_dir: /opt

m_monit_dirname: "mmonit-3.5.1"
m_monit_dir_tar_gz: "{{ m_monit_dirname }}.tar.gz"

Con esto ya tendríamos preparada la configuración de la máquina virtual y el aprovisionamiento de las máquinas.


6. Creación del entorno

Ahora que tenemos la configuración preparada, vamos a crear el entorno y ver qué nos ofrece la interfaz de M/Monit. Para crear el entorno basta con ejecutar el comando:

Terminal
vagrant up

Una vez haya terminado, vas a tener Nginx funcionando en la url localhost:8888.

Nginx default image

Y M/Monit en la url http://192.168.33.26:8080/.

M/Monit login page


7. Exploración de la interfaz de M/Monit

Por último vamos a navegar por la interfaz de M/Monit para ver qué nos ofrece. Para ello hacemos login con el usuario admin y la contraseña swordfish (Usuario administrador por defecto) y accedemos al dashboard.

Monit Dashboard

En este panel comprobamos el 100% de nuestros hosts (el único que envía datos está bien). Esto quiere decir que Monit está enviando información sobre el estado del servicio que monitoriza (Nginx), que ya hemos comprobado que funciona. A la derecha tenemos un panel de eventos en las últimas 24 horas, donde vemos el primer evento que es el envío de información del cliente al servidor.

Ahora accedemos a la pestaña status, donde tenemos un listado de todos los host que están enviando información al servidor. Como vemos solo tenemos el host “monit”, nombre que le pusimos en el Vagrantfile cuando lo creamos. También nos indica el consumo de cpu y de memoria, así como los eventos que se han producido en este host y su estado. En este caso, los dos servicios están disponibles (¿dos? exacto, el propio Monit y Nginx).

Monit Status

Si hacemos click en el host, veremos la información del host más detallada, y además podremos interactuar con los servicios que se monitorizan pudiendo pararlos, arrancarlos y reiniciarlos, monitorizarlos o dejar de hacerlo sin tener que entrar directamente.

Monit Status Detail

Ahora accedemos al apartado de reports donde podemos ver las analíticas y podemos jugar con ellas, parecido a las gráficas que te generas en Kibana.

Monit Report

Vamos a ver un ejemplo de como se ven los gráficos:

Monit Host Analytics

Ahora accedemos a el panel de administración general donde podemos ver la información general de Monit, las sesiones activas, la localización de los logs, y un pequeño apartado de preferencias en el cual podemos decir con qué frecuencia se borran los eventos.

Si ponemos el ratón sobre la pestaña admin, nos salen más opciones que podemos explorar. Vamos a ir viéndolas en orden descendente.

Monit admin options

En la pestaña hosts vemos las máquinas que tienen agentes de Monit instalados y comunicándose con M/Monit. Si hacemos click en el nombre de la máquina nos lleva al detalle que ya habíamos visto previamente.

Monit admin hosts

En la pestaña groups podemos definir una serie de máquinas agrupadas por tipo de instancia, contenido o un motivo de organización. De esta forma, también puedes crear reglas que apliquen a todo el grupo.

Monit admin groups

En la pestaña users es donde podemos crear usuarios para acceder a M/Monit. Yo os recomiendo como mínimo tener dos usuarios (con credenciales diferentes de las de por defecto, claro): uno que es el que usarán los agentes de Monit y otro para que podáis acceder a este panel.

Monit admin users

Por último tenemos las alertas, donde podemos definir avisos sobre eventos que le hayan sucedido a los servicios monitorizados de una máquina, grupos de hosts, y el método de aviso, que puede ser desde notificar con un correo electrónico (como tenemos configurado Monit), hasta que envíe mensajes por Slack. El grado de personalización de las alertas es muy amplio.

Monit admin alerts


8. Conclusiones

Al igual que Monit es muy sencillo y nos permite monitorizar el estado de nuestras aplicaciones o servicios y tomar decisiones respecto a su estado, M/Monit es una herramienta que nos ayuda a centralizar toda esta información que explotamos de los agentes.

Sin duda, si estás comenzando con el campo de monitorización de tus aplicaciones, o te preocupa que el servicio de las mismas pueda caerse cuando no estás disponible, es un primer paso para hacer que tu sistema sea más fiable.

El código completo (también el rol de Nginx y de Monit que no se han mostrado) están en mi repositorio de GitHub, de forma que solo hay que bajárselo y seguir las instrucciones desde el punto 6. Creación del entorno.


9. Referencias

Integración de Keycloak con AngularJS y Spring Boot

$
0
0

Índice de contenidos.


1. Introducción

Keycloak es la solución open source de autenticación y autorización centralizada de RedHat. Agnóstica de cualquier tecnología, las principales características que ofrece son:

  • Single-Sign On y Single-Sign Out para aplicaciones web y Apps.
  • Soporte OpenID Connect, OAuth 2.0 y SAML.
  • Identity Brokering – Autenticación por medio de un conector OpenID externo o por SAML Identity Providers.
  • Social Login – Habilitar la gestión de login Google, GitHub, Facebook, Twitter y otras soluciones de redes sociales.
  • User Federation – Sincronización de usuarios desde LDAP y Active Directory servers o RDBMS.
  • Kerberos bridge – Autenticar automáticamente a los usuarios que han iniciado sesión en un servidor Kerberos.
  • Consola de administración para la gestión centralizada de usuarios, roles, el mapeo de roles / usuarios, clientes (aplicaciones) y configuración.
  • Consola de administración de cuentas que permite a los usuarios gestionar de forma centralizada su cuenta.
  • Theme support – Personalizar todas las páginas de los distintos workflows (login, account, admin, email y welcome).
  • Two-factor Authentication – Soporte para TOTP/HOTP via Google Authenticator o FreeOTP.
  • Login flows – flujo de login configurable en un solo click opcional auto-registro de usuario, recuperación de contraseña, verificación de correo, actualización de password obligatorio, etc.
  • Session management – Los administradores y los propios usuarios pueden ver y gestionar las sesiones de usuario.
  • Token mappers – Mapeo de los atributos de usuarios, roles, etc., como uno lo desea en el token. Permite enriquecer el token.
  • Políticas de revocación para realm, aplicaciones y usuario.
  • Soporte CORS – Client adapters que han incorporado el soporte para CORS.
  • Service Provider Interfaces (SPI) – un framework SPI que permite la personalización de los diversos aspectos del servidor. Flujos de autenticación, user federation providers, protocol mappers y mucho más.
  • Client adapters para aplicaciones JavaScript, servidores WildFly, JBoss EAP, Fuse, Tomcat, Jetty, Spring, etc.

En este tutorial veremos cómo integrar keycloak con un front-end AngularJS y un back-end Spring Boot.

2. Entorno.

El tutorial ha sido escrito usando el siguiente entorno:

  • Maven (Version 3.3.9)
  • Spring Boot (Version 1.4.0.RELEASE)
  • Keycloak (Version 2.1.0.Final)
  • AngularJS (Version 1.5.0)

3. Creación de la política de autenticación y autorización en keycloak.

Una vez descargado e instalado el servidor keycloak, arrancamos el servidor ejecutando el script standalone.sh presente en la carpeta bin.

keycloak-angularjs-springboot_00

Una vez arrancado …

keycloak-angularjs-springboot_01

Abrimos el navegador e ingresamos en la consola de administración http://localhost:8080

Si es la primera vez, hay que crear previamente un usuario administrador (por ejemplo admin/admin)

keycloak-angularjs-springboot_02

Después de crear el usuario administrador, ingresamos en la consola de administración con este usuario pinchando en el enlace Administration Console. Por defecto keycloak utiliza un realm llamado master para gestionar sus propios usuarios. Por evitar cualquier interacción con este realm, es mejor crear uno propio.

Pasando el ratón sobre el realm Master, aparece un menu contextual con la opción Add realm.

keycloak-angularjs-springboot_03

Pinchando sobre la opción, aparecerá a la derecha un formulario donde indicaremos el nombre del nuevo realm que queremos crear.

keycloak-angularjs-springboot_04

A continuación, la consola de administración, una vez el realm creado, nos redirecciona sobre la página de configuración de este ultimo.

keycloak-angularjs-springboot_05

Seleccionamos el TabPanel Login y activamos las opciones de login User Registration y Forgot Password. En 3 clicks hemos añadido al flujo de login los típicos casos de uso de Alta de usuario y Olvido de contraseña.

keycloak-angularjs-springboot_06

4. Creación de roles en keycloak.

Ahora, vamos a añadir algunos roles aplicativo que se asignarán a usuarios mas adelante. Creamos dos roles, uno como super manager y otro como manager.

Seleccionamos la opción Roles en el panel de configuración, pulsamos en el botón Add Role en la parte derecha de la pantalla. Esto nos llevará hasta la pantalla Add Role. Introduzcamos super manager como nombre del primer rol y Guardamos. Creamos un segundo rol de nombre manager, aplicando la misma operativa

keycloak-angularjs-springboot_07

5. Creación de clientes en keycloak.

La noción de cliente en keycloak corresponde a una unidad de negocio de tipo front-end, back-end, microservicio o no.

Para este tutorial necesitamos crear dos clientes. Uno para el front-end de nuestra aplicación y otro para el back-end.

Seleccionamos la opción Clients en el panel de configuración, pulsamos en el botón Create en la parte derecha de la pantalla. Esto nos llevará hasta la pantalla Add Client.

Introduzcamos como client id account-front-end y guardamos.

keycloak-angularjs-springboot_08

La consola de administración nos redirecciona automáticamente al TabPanel Settings de la opción Clients. En la configuración, verificamos que la opción public del combobox Access Type está selecccionada.

Rellenamos los campos Valid Redirect URIs, Base URL y Web Origins con los siguientes valores

  • Valid Redirect URIs: http://localhost:8000/*
  • Base URL: http://localhost:8000/index.html
  • Web Origins: http://localhost:8000
  • Como es lógico de entender, esto indica que nuestra aplicación front-end debe ejecutarse en esta dirección

    keycloak-angularjs-springboot_09

    Ahora el cliente front-end está completamente configurado y se puede utilizar.

    Vamos ahora crear otro cliente para el back-end de nuestra aplicación de nombre account-backend. Esta vez en la configuración seleccionamos la opción bearer-only en el combobox Access Type porque el back-end REST sólo debe ser invocado cuando un usuario ya está autenticado, por supuesto sin olvidarnos de guardar los cambios.

    keycloak-angularjs-springboot_10

    Ahora podemos dar por finalizado la configuración en el servidor Keycloak y atacar la integración de los adaptadores keycloak en nuestra aplicación.


    6. Integración en el front-end AngularJS.

    Keycloak proporciona un adaptador javascript que permite la comunicación entre el front-end y el servidor keycloak. Este adaptador permite, entre otras cosas, comprobar si el usuario está autenticado.

    Lo primero, declaramos en la cabecera de nuestro fichero index.html (head) el fichero keycloak.js

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>Account Demo
            <meta name="viewport" content="initial-scale=1.0, user-scalable=yes">
            <script src="//localhost:8080/auth/js/keycloak.js">
            <script src="js/lib/angular-1.5.0.min.js">
    		<script src="js/lib/angular-route-1.5.0.min.js">
            <script src="js/main.js">
            <script src="js/main-controller.js">
        </head>
        <body>
    		<div ng-view>
        </body>
    </html>

    En segundo lugar, tenemos que proporcionar al adaptador keycloak la configuración del servidor de identidad en un fichero con formato JSON.

    Para obtener el archivo JSON, abrimos la consola de administración de keycloak y vayamos a la página del cliente account-frontend. A continuación, abrimos la pestaña Installation y elegimos la opción de formato Keycloak OIDC JSON.

    keycloak-angularjs-springboot_11

    Descargamos el archivo JSON y lo guardamos en la ruta /keycloak/keycloak.json por debajo de la webapp.

    keycloak-angularjs-springboot_12

    En el tratamiento del front, cargamos la configuración del servidor de identidad en un objeto _keycloak.

    Para asegurarse que damos paso únicamente a un usuario autenticado, vamos a arrancar la aplicación angularjs manualmente una vez autenticado. En caso contrario se producirá un redirect a la página de login del servidor keycloak.

    // on every request, authenticate user first
    angular.element(document).ready(() => {
    	window._keycloak = Keycloak('keycloak/keycloak.json');
    
    	window._keycloak.init({
    		onLoad: 'login-required'
    	})
    	.success((authenticated) => {
    		if(authenticated) {
    			window._keycloak.loadUserProfile().success(function(profile){
    				angular.bootstrap(document, ['account-demo']); // manually bootstrap Angular
    			});
    		}
    		else {
    			window.location.reload();
    		}
    	})
    	.error(function () {
    		window.location.reload();
    	});
    });

    Para recuperar la información relativa al usuario autenticado podemos utilizar la función javascript loadUserProfile proporcionada por el adaptador. Eso es básicamente todo lo que se necesita para securizar un front-end angularjs.

    Para asegurarnos que transmitimos la información relativa al usuario autenticado al back-end vamos añadir en la cabecera http del httpProvider el token generado por el servidor, siempre cuando este último no expire.

    // use bearer token when calling backend
    app.config(['$httpProvider', function($httpProvider) {
    	var isExpired = window._keycloak.isTokenExpired();
    	var token = window._keycloak.token;
    
    	if (sExpired) {
    		window._keycloak.updateToken(5)
    		.success(function() {
    			$httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
    		})
    		.error(function() {
    			console.error('Failed to refresh token');
    		});
    	}
    
    	$httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
    }]);

    7. Integración en el back-end Spring Boot.

    Al igual que en el front-end, el back-end debe protegerse contra acceso no autorizado. Por lo tanto, sólo los usuarios autenticados deben ser aceptados.

    En primer lugar, debemos declarar en el pom.xml del proyecto las dependencias keycloak de Tomcat y de Spring Boot.

    <dependency>
    	<groupId>org.keycloak
    	<artifactId>keycloak-tomcat8-adapter
    	<version>${keycloak.version}
    </dependency>
    <dependency>
    	<groupId>org.keycloak
    	<artifactId>keycloak-spring-boot-adapter
    	<version>${keycloak.version}
    </dependency>

    Al igual que en el front-end, debemos proporcionar la configuración del servidor de identidad al back-end para poder comunicarnos con él.

    Declaramos esta configuración en el fichero application.properties de Spring Boot. Estas son las propiedades de keycloak.

    keycloak.realm = autentia
    keycloak.realmKey = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiwBRXJWQu0XYIRoCen+2vmEMtkAXBs1nnIQQHJ0/IxxnVP9LwJUOX2/PYBBAaQlF2NEpTh2jMXAdPOwBDF8Vrc+25cbWIW47keUlNPmvZIMWJORIbcYmMZBBJrolSe3P5M3K8Lu75MLf1Fo6OQ6I+h0QSaifj8EQUBOYhXFL9enlC89HIHtAdddmVLPtMy2yoDFgzU8KKgo3bH0lbay8iwOrk+EHlorZHivfMjC8z1fhQq4d3aV9KXyhWQPs//SZLb+f4KcKVzdu43zA4r3UICml/JAPhP9LWIQXJXJ/Y6i90Ye4hUhXrQEe0N2I/C8w6Z9TOeYA6pp1WEktsnT7WwIDAQAB
    keycloak.auth-server-url = http://localhost:8080/auth
    keycloak.ssl-required = external
    keycloak.resource = account-backend
    keycloak.bearer-only = true
    keycloak.credentials.secret = 9801d0f9-710e-41ca-aba1-d83e20892b55

    Los valores se pueden recuperar desde la consola de administración en la pestaña Installation del cliente account-backend.

    Lo más importante, no olvidar el valor de la propiedad credentials.secret del cliente back-end, pestaña Credentials.

    keycloak-angularjs-springboot_13

    Para proteger nuestra API REST, podemos declarar las siguientes propiedades en el fichero de configuración application.properties.

    keycloak.securityConstraints[0].securityCollections[0].name = spring secured api
    keycloak.securityConstraints[0].securityCollections[0].authRoles[0] = super manager
    keycloak.securityConstraints[0].securityCollections[0].authRoles[1] = manager
    keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /api/*

    Con esta declaración, estamos delegando en el servidor keycloak la política de autorización de nuestra API REST. Al igual que en Spring Security, estamos obligando a que el usuario autenticado tenga además uno de los dos roles especificados en la configuración. Si la configuración es correcta el adaptador Spring Boot se encargará de interceptar las peticiones entrantes y rechazará las solicitudes no autorizadas.

    keycloak-angularjs-springboot_14

    Para poder recuperar la información relativa al usuario conectado en el back-end, el adaptador Spring Boot ofrece un objeto KeycloakPrincipal que se puede recuperar del contexto de seguridad. Implementamos un MethodArgument Resolver de Spring que se encargará de crear un objeto UserDetails a partir del objeto KeycloakPrincipal y lo inyectamos por medio de una anotación personalizada en cualquier método de un Controlador REST que lo necesite.

    Para más información, os invito a consultar el código proporcionado en la siguiente dirección.


    8. Demo.

    Para arrancar la demo, lo primero nos bajamos los fuentes de la aplicación del repositorio Github.

    keycloak-angularjs-springboot_15

    A continuación, podemos configurar la aplicación de front-end y back-end con la configuración correcta de Keycloak como se ha descrito anteriormente o utilizamos la configuración existente proporcionada en el fichero keycloak/autentia-realm.json del proyecto, importándolo en el servidor Keycloak. A continuación, abrimos una consola y nos posicionamos en la raíz del proyecto. Arrancamos la aplicación con el siguiente comando de maven.

    keycloak-angularjs-springboot_16

    Abrimos el navegador y vamos a la dirección http://localhost:8000.

  • La aplicación nos mandará a la página de login del servidor keycloak.
  • Nos registramos como nuevo usuario. Al finalizar el proceso, el servidor keycloak nos mandará de vuelta a la aplicación donde veremos algunos detalles acerca del usuario.
  • keycloak-angularjs-springboot_17

    De momento el usuario no tiene ningún rol aplicativo asociado y como consecuencia no tiene los permisos adecuados para poder ejecutar cualquier lógica de negocio presente en el back-end.

    Para ello, abrimos la consola de administración del servidor Keycloak y vayamos a la opción Users. A continuación, pulsamos en el botón View all users y seleccionamos el usuario autenticado. Después ir a la pestaña Role Mappings, asignamos el rol de super manager al usuario.

    keycloak-angularjs-springboot_18

    Volvemos a refrescar el navegador donde se ejecuta la aplicación (F5) et voilà, ya tenemos los permisos suficientes para ejecutar la lógica de negocio del back-end.

    keycloak-angularjs-springboot_19

    9. Referencias.


    10. Conclusiones.

    Hemos visto una solución simple, poco intrusiva y poco costosa de SSO centralizado, securizando un front-end AngularJS y un back-end Spring Boot con el soporte de keycloak.

    Un saludo.

    François

    Generar cuenta atrás con Adobe After Effects CC

    $
    0
    0

    Este tutorial explica cómo generar y modificar una cuenta atrás en adobe After Effects mediante el uso de expresiones

    Índice de contenidos


    1. Introducción

    En muchas ocasiones, cosas que parecen muy fáciles de realizar pueden llegar a complicarse o ser más difíciles de lo que parecían a primera vista. Esto fue lo que me sucedió cuando intenté generar una cuenta atrás con After Effects.

    El planteamiento era sencillo, un número que se reduzca a tiempo real y que pudiera parar y reanudar cuando yo quisiera.

    Por ello, tras encontrar con la ayuda de un compañero una forma de hacerlo relativamente sencilla, aprovechando la posibilidad que nos da el programa de añadir expresiones, decidí compartir este tutorial.

    Hay dos modos de hacer un contador:

  • 1. Relacionando nuestra variable con el paso del tiempo en el timeline.
  • 2. Dando valores a los keyframes e interpolando esos valores.

  • El primero es más sencillo de usar pero más complejo de programar. El segundo es fácil de programar pero requiere que coloquemos los keyframes en el sitio adecuado para simular el paso del tiempo, y este es el supuesto que vamos a explicar.


    2. Entorno

    El tutorial está escrito usando el siguiente entorno:

    • Hardware: Portátil MacBook Pro 15′ (2,2 Ghz Intel Core i7, 8GB DDR3).
    • Sistema Operativo: Mac OS El Capitán 10.11
    • Entorno de desarrollo: Adobe After Effects CC

    3. Crear proyecto

    En primer lugar creamos un nuevo proyecto en After Effects y una nueva composición, con las características que queramos que tenga nuestra imagen de resolución y tamaño:

    Foto 1

    En este caso hemos creado un fondo blanco con una resolución de 1920 x 1080, es decir full HD.

    Con la herramienta texto horizontal añadimos un número con la tipografía, tamaño y color que queramos (el número es indiferente ya que tras añadir la expresión cambiará).


    4. Añadir la expresión

    Lo primero que tenemos que hacer es añadir el efecto “Control de deslizador” si nuestro programa está en español, o “Slider control” si lo tenemos en inglés a nuestra capa texto.

    Lo que haremos será utilizar este efecto para controlar nuestra cuenta atrás.

    Para añadir expresiones en Adobe After Effects tenemos que pulsar con la tecla ALT en el cronómetro de la característica a la que se lo queramos añadir, en este caso desplegaremos las opciones de la capa texto y con ALT pulsado pinchamos en el cronómetro de “Texto de origen”

    Foto 2

    Nos saldrá entonces un espacio en el que podemos escribir, para facilitar la tarea ampliamos el ancho del espacio y pegamos el siguiente texto:

  • En el caso de After Effects en español:
  • function padZero(n){
        if (n < 10) return "0" + n else return "" + n
    }
    
    t = Math.floor(effect("Control del deslizador")("Deslizador"));
    sec = Math.floor(t%11);
    padZero(sec)
  • Si tenemos el programa en inglés:
  • function padZero(n){
        if (n < 10) return "0" + n else return "" + n
    }
    
    t = Math.floor(effect("Slider Control")("Slider"));
    sec = Math.floor(t%11);
    padZero(sec)

    En caso de que no queramos que nuestra cuenta atrás tenga dos cifras siempre, bastaría con usar la siguiente parte de la expresión:

    t = Math.floor(effect("Control del deslizador")("Deslizador"));
    sec = Math.floor(t%11);
    Foto 3

    5. Modificar los parámetros

    Como habréis comprobado, una vez añadida la expresión el número que hayáis puesto habrá cambiado a 0, esto es por qué los cambios los hacemos desde la propia expresión.
  • sec = Math.floor(t%11);

  • Para cambiar el número que queremos que aparezca, en nuestra expresión tenemos que poner en la línea sec siempre un número más del que queremos que sea nuestro número inicial (en este caso hemos puesto 11 ya que queremos hacer una cuenta atrás desde 10).

    Para animar esta cuenta atrás lo haremos mediante Keyframes o fotogramas clave.

    Para ello desplegamos en la capa efectos y control de deslizador y nos saldrá la opción deslizador con el cronómetro.

    Foto 4

    Para que nuestra cuenta atrás comience en 10 cambiamos el número del deslizador a 10 (si ponemos 11, que es el número de la expresión nos saldrá un 0) y pulsamos el cronómetro, lo que nos creará un keyframe.

    Después llevamos nuestro cursor al segundo 10 y cambiamos el número del deslizador a 0, de este modo tendremos la cuenta atrás a tiempo real.

    Foto 5

    6. Parar la cuenta atrás

    En algunos casos, querremos parar nuestra cuenta atrás y reanudarlas después, esto es algo más complicado ya que para mantener el tiempo real tendremos que realizar algunos cálculos.

    Por ejemplo, si cuando llega al número 6 queremos realizar un parón, y que en el segundo 10 se reanude de nuevo hasta llegar a 0, tenemos que hacer lo siguiente:

  • Colocamos nuestro cursor en el segundo 4 y añadimos un keyframe nuevo pulsando el rombo de la izquierda.
  • Nos movemos hasta donde queramos reanudar nuestra cuenta atrás, por ejemplo al segundo 10, y ponemos el número del deslizador en 6
  • Por último avanzamos 6 segundos y colocamos el deslizador en 0 para que continúe la cuenta atrás.

  • Foto 6b

    7. Conclusiones

    Como veis, no es una manera demasiado complicada de generar una cuenta atrás, si que es cierto que en el caso de que queramos pararla y reanudarla varias veces o si lo hacemos con números más grandes habría que realizar algunos cálculos.

    !Espero que os haya servido este tutorial!

    Un reto de concurrencia – System.arraycopy()

    $
    0
    0

    “Los amigos de verdad no se dejan escribir concurrencia a bajo nivel”. – @karianna. Aquí tienes tu oportunidad para participar en una revisión global de código y tratar de averiguar qué está ocurriendo en código sincronizado.

    Éste artículo es una traducción al castellano de la entrada original publicada, en inglés, por Dr. Heinz Kabutz en su número 241 de The Javatm Specialists’ Newsletter. Puedes consultar el texto original en Javaspecialists’ Newsletter #241: Concurrency Puzzle – System.arraycopy()

    Este artículo se publica traducido en adictos, con permiso del autor, por David Gómez García, (@dgomezg) consultor tecnológico en Autentia, colaborador de JavaSpecialists e instructor certificado para impartir los cursos de JavaSpecialists.

    Bienvenidos a la edición número 241 de The Javatm Specialists’ Newsletter, escrito desde Chorafakia, Creta. La tarde antes del inicio de nuestra conferencia JCrete, tropecé mientras corría, y me hice un esguince en el pie izquierdo. Entré en pánico. Setenta asistentes de 25 países distintos me esperaban. Elegidos cada uno de ellos a mano. Teníamos excursiones que hacer, playas lejanas, ruinas antiguas que explorar… Así que tomé el consejo del entrenador de baloncesto de mi hijo: spray de hielo para reducir el dolor tan rápidamente como fuese posible. Las instrucciones estaban en griego. ¿pero tan complicado iba a ser?. Apunta, pulveriza y ¡Listo!. Salvo que que debería haerlas leido. Me produje una quemadura de tal tipo que todavía dos meses después mi fisioterapeuta me desaprueba con la cabeza cuando me ve. La caída fue relativamente pequeña. La quemadura no. ¡Leed siempre las instrucciones!. El mismo consejo sirve para el código concurrente. Puedes achicharrarte gravemente sin darte cuenta. Tú código puede que funcione en tu equipo, pero fallar en el servidor



    NOVEDAD Echa un vistazo a nuestro nuevo curso “Extreme Java“, que combina concurrencia, un poco de de rendimiento y Java 8: “Extreme Concurrency & performance course for Java 8”, que también impartimos en castellano.


    Un problema de concurrencia – System.arraycopy()

    Hemos tenido hace poco un divertido debate en Twitter sobre la importancia de la revisión de pares en el código concurrente. Es muy fácil cometer errores, incluso para los programadores más experimentados. Escribir código concurrente se parece un poco a bucear en cuevas: sólo el aficionado piensa que tiene la capacidad suficiente para ir solo.

    Mi buen amigo Jack Shirazi me ha enviado un pequeño código que habíamos preparado juntos. Siendo el Jack de JavaPerformanceTuning.com, obviamente él ya sabía que el cuello de botella estaba en la creación de objetos, no en la contención. También era consciente de que el paralelismo era incorrecto. No obstante, al idear su experimento, encontró un caso muy interesante de escritura temprana en System.arraycopy(), debido a las líneas de caché, a hilos cambiando de núcleo, a la limpieza, etc…. Creo que le dejaré explicarse:

    “Estaba jugando con locks separados para lecturas y escrituras, para un ejemplo en el que estoy pensando, y me encontré este fallo de concurrencia que no pude explicar. (Si no estás interesado no hay problema, es sólo una rareza fruto de una incorrecta implementación, así que no es algo tan útil). La clase está adjunta. Básicamente debería ser una clase thread-safe para una especie de arraylist para enteros con segmentación de monitores si uso un sólo lock, pero trataba de entender dónde se produciría el fallo de concurrencia si los hilos de lectura y los de escritura usaban distintos locks.

    “Y lo que veo es que el hilo de lectura rara vez ve un elemento de array vacío, una vez que ha sido rellenado. No me sorprende que vea un estado corrupto, pero no puedo imaginarme cómo se puede llegar a ese estado corrupto. Quizá estoy poniendo demasiado esfuerzo simplemente en comprender una implementación incorrecta. Un par de cosas que he probado: como array de Objetos (más que array de int), obtengo el mismo fallo (ver un valor nulo); sin el método remove(), de nuevo lo veo, solo que menos a menudo.

    Casi pareciera que System.arraycopy() establece un array vacío en el que copia los datos (posible), lo que estaría bien dentro de un bloque sincronizado, no verías ningún efecto, pero es como si ese array vacío se escapase a la memoria ‘principal’ antes de que el bloque sincronizado acabe, y el hilo de lectura lo ve.

    “Mi mejor teoría es que el hilo de escritura está ocupado escribiendo y que escribe en la caché L1, vaciando primero la linea de cache, entonces, antes de escribir los datos, queda suspendido (hay muchas ejecuciones del GC); el hilo de lectura está también suspendido en una lectura; cuando los hilos son re-iniciados, el SO arranca el hilo de lectura en el núcleo en el que la escritura fue suspendida, y dado que no ha habido un vaciado del hilo de lectura que invalidase los contenidos de memoria de la cache, por eso el hilo de lectura asume que es válido y simplemente usa ese valor vacío.” – Jack Shirazi

    Heinz de nuevo :-). Ejecuté el código en mi MacBookPro Retina Display y no me devolvió los resultados que él estaba obteniendo. Lo ejecuté después en mi servidor 2-4-1 (8 nucleos) en el que se hospeda JavaSpecialists.eu y allí pude ver que, de hecho, algunas veces get() devolvía 0 cuando obviamente no debería. Así que es posible que necesites ejecutar el código en varias máquinas distintas hasta que puedas reproducirlo.

    En lugar de simplemente proporcionar una explicación detallada, pensé que sería más divertido si os meto en la cueva de la programación concurrente con nosotros e intentamos averiguar cómo System.arraycopy() puede, en ocasiones, realizar escrituras tempranas y dejar escapar arrays sin inicializar accesibles para los hilos de lectura. ¿quizá mirando al código C de System.arraycopy() o utilizando JITWatch para ver el código máquina generado?. La primera persona que me envíe una explicación correcta, se ganará una mención en el próximo artículo. Si estás suscrito al newsletter por email, simplemente responde al correo. En otro caso, por favor, registrate aquí y responde al correo de bienvenida. Date prisa, hay cientos de desarrolladores Java leyendo esto como tú, deseando ser inmortalizados en el The Javatm Specialists’ Newsletter :-). Un segundo reto para aquellos de vosotros que estáis despiertos a estas horas es enviarme una solución que use StampedLock. Para ganar puntos extra, actualiza el lock en el método remove()

    import java.util.*;
    
    	public class MyArrayList {
    	  private final Object READ_LOCK = new Object();
    	  private final Object WRITE_LOCK = new Object();
    	  private int[] arr = new int[10];
    	  private int size = 0;
    
    	  public int size() {
    	    synchronized (READ_LOCK) {
    	      return size;
    	    }
    	  }
    
    	  public int get(int index) {
    	    synchronized (READ_LOCK) {
    	      rangeCheck(index);
    	      return arr[index];
    	    }
    	  }
    
    	  public boolean add(int e) {
    	    synchronized (WRITE_LOCK) {
    	      if (size + 1 > arr.length)
    	        arr = Arrays.copyOf(arr, size + 10);
    
    	      arr[size++] = e;
    	      return true;
    	    }
    	  }
    
    	  public int remove(int index) {
    	    synchronized (WRITE_LOCK) {
    	      rangeCheck(index);
    
    	      int oldValue = arr[index];
    
    	      int numMoved = size - index - 1;
    	      if (numMoved > 0)
    	        System.arraycopy(arr, index + 1,
    	            arr, index, numMoved);
    	      arr[--size] = 0;
    
    	      return oldValue;
    	    }
    	  }
    
    	  private void rangeCheck(int index) {
    	    if (index >= size)
    	      throw new IndexOutOfBoundsException(
    	          "Index: " + index + ", Size: " + size);
    	  }
    
    	  public static void main(String[] args) {
    	    for (int i = 0; i < 100000; i++) {
    	      MyArrayList list = new MyArrayList();
    	      new Thread(new Main(list, true)).start();
    	      new Thread(new Main(list, false)).start();
    	      new Thread(new Main(list, false)).start();
    	    }
    	  }
    
    	  static class Main implements Runnable {
    	    MyArrayList list;
    	    boolean update;
    
    	    public Main(MyArrayList list,
    	                boolean update) {
    	      this.list = list;
    	      this.update = update;
    	    }
    
    	    @Override
    	    public void run() {
    	      if (update) {
    	        for (int i = 1; i < 1000; i++) {
    	          list.add(i);
    	        }
    	        for (int i = 1; i < 250; i++) {
    	          list.remove(7);
    	        }
    	      } else {
    	        // wait until we're certain
    	        // index 6 has a value
    	        while (list.size() < 7) {}
    	        for (int i = 1; i < 1000; i++) {
    	          int x;
    	          if ((x = list.get(6)) != 7) {
    	            System.out.println(x +
    	                " and " + list.size());
    	          }
    	        }
    	      }
    	    }
    	  }
    	}

    Disclaimer: Jack Shirazi me ha permitido amablemente republicar este correo y el código. La clase que me ha enviado es un experimento y no es indicativo de lo que escribe habitualmente :-). Sé exactamente que es lo que está ocurriendo y por qué, dado que se explica en el capítulo 2 de mi curso “Extreme Concurrency & performance course for Java 8”, que también impartimos en castellano. Estoy convencido de que muchos de vosotros lo averiguareis también pero, por favor, tened espíritu deportivo y no publiquéis vuestras ideas hasta que hayamos anunciado el ganador. Paciencia, paciencia, paciencia :-)

    Saludos

    Heinz.

    P.D. Si todavía no te has apuntado a la newsletter mensual de Jack Shirazi, te recomiendo fuertemente que lo hagas. Aquí tienes el enlace: Java Performance Tuning News


    Crear efecto visión Terminator con After Effects CC

    $
    0
    0

    En este tutorial voy a tratar de explicar de forma clara cómo conseguir el efecto de visión de terminator con After Effects para que podáis usarlo en vuestros vídeos.

    Captura de pantalla 2016-08-30 a las 9.00.18   Captura de pantalla 2016-08-30 a las 8.59.45

    Paso por paso

    Lo primero que tenemos que hacer es grabar el vídeo con el que queramos trabajar. Lo recomendable es que en el vídeo aparezcan personas que se muevan un poco para que el efecto de tracking que explicaré más adelante sea más dinámico.

    Importamos el vídeo y creamos una composición llamada FOOTAGE (así es como la he llamado yo) y en la que vamos a meter el vídeo que hayamos grabado y lo duplicamos de forma que tengamos dos capas de vídeo. Buscamos un punto en él donde vamos a hacer un corte que será el punto donde empezará el efecto de interferencia que vamos a ver a continuación. Seleccionando las dos capas de vídeo damos a botón derecho y PRECOMPONEMOS la capa de FOOTAGE. Cuando lo tengamos creamos otra composición llamada COMP 1 y metemos en ella la precomposición.

    Captura de pantalla 2016-08-29 a las 13.15.26

    Dentro de COMP 1 con la capa de la precomposición de FOOTAGE vamos a seleccionar el efecto teñir:

    • Efecto – Corrección de color
      • Teñir

    Cambiamos el color blanco por el rojo y quitamos un poco de nivel de tinción


    Capa de SCANLINES

    Creamos un nuevo sólido:

    • Capa – nuevo sólido blanco llamado SCANLINES
      • Efecto – generar
        • Cuadrícula

    En el panel de la izquierda de Controles y efectos- scanlines:

    – Tamaño desde: Anchura y altura de los reguladores
    – Anchura 4000
    – Altura 10
    – Movemos el punto de anclaje hacia la derecha
    – Borde 3
    – Opacidad 58%


    Capa de ESTÁTICO

    Ahora vamos a crear un efecto de imagen borrosa, como una interferencia que durará milésimas de segundos.

    • Capa – nuevo sólido blanco llamado ESTÁTICO
      • Efecto – Ruido y Grano
        • Ruido HLS
        Captura de pantalla 2016-08-29 a las 13.26.37

        En el panel de la izquierda de Controles y efectos – estático:
        – Ruido: Granulado
        – Luminosidad 616%
        – Tamaño del granulado: 1,91

        Vamos a meter otro efecto:

        • Efecto – distorsionar
          • Desplazamiento turbulento

        En el panel de la izquierda de Controles y efectos – estático:
        – Desplazamiento: desplazamiento horizontal
        – Nivel 10000
        – Tamaño 27
        – Complejidad 4,5
        – Borde 3
        – Opacidad 40%

        Ahora está estático, para darle movimiento vamos a animar la evolución. Vamos a usar las expresiones de after effects que se sacan manteniendo pulsado ALT (en mac) y el reloj del efecto que queremos animar. En el timeline de las capas aparecerá una expresión effect(*Turbulent Displace*)(6) y eso lo reemplazamos por time*1000

        Captura de pantalla 2016-08-29 a las 13.33.34

        Capa de AJUSTE ESTÁTICO

        El siguiente paso es añadir la capa de ajuste estático. Tenemos que ir fijándonos en el orden en el que vamos teniendo las capas en el timeline. Deben estar ordenadas de esta forma: Scanlines, Ajuste estático, Estático, Footage

        Antes de hacer nada en esta nueva capa vamos a seleccionar la capa de estático y nos vamos a copiar el efecto de Desplazamiento turbulento de la ventana de la izquierda de Controles de efectos: cmd+c para copiar. Nos vamos a la capa de ajuste estático y pegamos el efecto con cmd+v

        En el panel de la izquierda de Controles y efectos – ajuste estático
        – Desplazamiento: desplazamiento horizontal
        – Nivel 500
        – Tamaño 27
        – Complejidad 4,5

        Vamos a crear un controlador en la capa de ajuste estático:

        • Efecto – expresiones de control
          • Control del deslizador

          Con ALT pulsado pinchamos en el reloj del efecto Desplazamiento turbulento (seguimos en la capa de ajuste estático), y nos aparecerá la expresión en el timeline. Cogemos la espiral que aparece en el apartado de Nivel y la llevamos al efecto Deslizador y en la expresión a continuación escribimos *5

          Captura de pantalla 2016-08-29 a las 13.51.05

          Vamos a la capa ESTÁTICO y con ALT pulsado pinchamos en el reloj de la opacidad para que aparezca la expresión, seleccionamos la capa de AJUSTE ESTÁTICO para que a la izquierda nos aparezca la ventana de Controles de efectos y enlazamos la espiral de la capa de ESTÁTICO en la opacidad con el Deslizador de la capa de AJUSTE ESTÁTICO y escribimos en la expresión *.4. Ahora el controlador, controla a las dos capas.

          Captura de pantalla 2016-08-29 a las 13.46.36

          Movemos un poco la barra en el timeline y desde la capa de AJUSTE ESTÁTICO ponemos un keyframe en el efecto Deslizador (pulsando el reloj), nos movemos 3 frames hacia adelante (pulsando cmd + →) y en deslizador ponemos el valor 100. Adelantamos otros 3 frames y en deslizador ponemos 0. Ya tendríamos el efecto de interferencias. Yo lo que he hecho ha sido copiar y pegar esos 3 keyframes a lo largo del timeline para tener varias interferencias durante el vídeo. Podéis hacer lo mismo y ponerlos donde decidáis

          Captura de pantalla 2016-08-29 a las 13.51.05

          Capa de OPTICS

          Capa – nueva capa de ajuste llamada OPTICS

          Ponemos esta capa la primera de todas.

          • Efecto – distorsionar
            • Compensación óptica

          En el panel de la izquierda de Controles y efectos – optics
          – Campo visual 65
          – Seleccionar “invertir distorsión de la lente”
          – Orientación horizontal


          Capa GUÍA

          Ocultamos la capa de OPTICS y sin tener ninguna capa seleccionada pinchamos en la herramienta rectángulo para crear una capa de formas. La llamamos guía. Borramos el relleno. Nos vamos a la capa de OPTICS y copiamos el efecto Compensación óptica y lo pegamos en la capa de forma de GUÍA y le quitamos la opción de “invertir distorsión de lente”. Ponemos la capa de forma por debajo de la capa de OPTICS.

          Cuando desocultemos OPTICS sabremos cómo será la visión. Recomiendo trabajar con la capa activa de GUÍA hasta el final y mantener oculta OPTICS. Mantenemos pulsado ALT en la capa de GUÍA y pinchamos en el reloj de Campo Visual. Llevamos la espiral a la capa de OPTICS al efecto Campo Visual.

          Captura de pantalla 2016-08-29 a las 13.59.22

          Con el botón derecho del ratón hacemos click en la capa de GUÍA y elegimos Capa de guía. Esto hará que la capa esté visible hasta que lo añadamos a la cola de procesamiento para renderizarlo.


          Bordes blancos de reconocimiento

          Los creamos sin seleccionar ninguna capa, de esta forma crearemos capas de forma. Usamos la herramienta pluma y vamos haciendo el borde en el objeto que queramos. Damos keyframes de posición al inicio y al final para que el trazo siempre esté bordeando al objeto y ponemos el trazo blanco. Cortamos la capa con la duración que queramos.

          Captura de pantalla 2016-08-30 a las 11.23.03

          Texto analysis

          Creamos una nueva capa de texto

          • Capa – nuevo texto llamado ANALYSIS

          Precomponemos la capa y entramos dentro de la composición

          Escribimos la palabra ANALYSIS y debajo asteriscos con la fuente OCR A Std. A continuación creamos otra nueva capa de texto y escribimos por ejemplo sfg y con la capa sfg seleccionada:

          • Efecto – Texto
            • Números

          Se nos abrirá una ventana y tendremos que poner la tipografía OCR A Std horizontal e izquierda y cuando le demos a aceptar, en la parte izquierda de controles de efectos:
          – Colocación decimal 0
          – Valor/Desplazamiento 2000

          Captura de pantalla 2016-08-29 a las 9.36.00

          Pulsamos ALT y pinchamos en el reloj del efecto Valor/Desplazamiento y escribimos en el rectángulo de la expresión lo siguiente: wiggle(15,2000)

          Captura de pantalla 2016-08-29 a las 9.32.01

          Este efecto se mueve independientemente, vamos que aparecen una serie de puntos rojos que si los desplazamos en la pantalla de composición se van a mover de manera independiente sin afectar a la serie de números que hemos creado. Vamos a abrir el efecto de Relleno y Trazo de la ventana de Controles de efectos a la izquierda y con ALT y el reloj de la posición vamos a sacar una expresión. La expresión que nos aparece la vamos a dejar tal y como está. Desplegamos en las capas la opción de Transformar y a la expresión le añadimos un signo de + y llevamos la espiral del efecto Relleno y Trazo a la opción de posición de Transformar. El siguiente paso es poner los valores de esa posición en 0 para que vuelva a aparecer el texto de números.

          Después de enlazar con la espiral la expresión nos debe quedar de la siguiente manera:

          effect(*Numbers*)(9)+transform.position

          Para corregir la posición y dejar el valor alineado con el texto de análisis, movemos a la posición desde la ventana de la izquierda de Controles y efectos y movemos los valores.

          El siguiente paso es duplicar el efecto de Números y ahora en la capa de Números 2 activamos la opción de Componer en original. Ahora vamos a modificar la expresión de la capa Números 2 porque al duplicar la capa se ha copiado la expresión de Números 1. Lo único que tendremos que hacer será añadir un 2:

          effect(*Numbers 2*)(9)+transform.position y mover la posición.

          Captura de pantalla 2016-08-29 a las 9.36.59

          Duplicamos la capa de sfg y movemos la posición en eje Y hacia abajo y duplicamos de nuevo la capa hasta tener 6 capas en total. Seleccionamos todas y las alineamos horizontalmente. Si reproducimos la composición los números deberían correr.

          Captura de pantalla 2016-08-29 a las 9.50.37
          Captura de pantalla 2016-08-29 a las 9.56.09   Captura de pantalla 2016-08-29 a las 9.56.18

          La primera imagen es como se ve con la capa de guía activada y la imagen de la derecha es como lo vemos cuando hacemos visible la capa de OPTICS

          Volvemos a COMP 1 y colocamos la composición de ANALYSIS debajo de la capa AJUSTE ESTÁTICO


          Capa Voice Analysis

          Estando en COMP 1 y yéndonos a la capa de la precomposición de FOOTAGE sacamos la forma de onda.

          • Efectos
            • Transformar
              • Audio
                • Forma de onda

            Creamos un nuevo sólido llamado VOZ:

            • Efecto – generar
              • Espectro de audio

            En el panel de la izquierda de Controles y efectos – footage
            – Capa de audio – Footage
            – Color interior blanco
            – Color exterior blanco

            Movemos los valores de Punto de inicio y Punto final para hacerlo más pequeño y la altura máxima la subimos para que sea más notable la forma de onda. El suavizado lo ponemos a 0 y en Opciones de Visualización que vendrá marcado Lado A y B elegimos sólo Lado A.

            Vamos a crear una caja alrededor de la forma de onda. Para ello hacemos doble click en la herramienta rectángulo con la capa de voz seleccionada para crear una máscara y NO una capa de forma.

            • Efecto – Generar
              • Trazo
            Captura de pantalla 2016-08-29 a las 10.01.43

            Tracking

            Buscamos el punto donde queremos que empiece el trackeo. En mi caso he decidido que empiece cuando aparece en plano la persona. Duplicamos la capa de FOOTAGE con cmd+d (la duplicada aparecerá debajo) cortamos la capa de arriba en el punto en el que empieza el trackeo con CTRL+cmd+D. Abrimos la ventana de Rastreador y seleccionamos Rastrear movimiento. Seleccionamos posición y escala. Colocamos los cuadrados en las esquinas de los ojos y le damos a Analizar. No tiene por qué ser perfecto el trackeo.

            Creamos nuevo sólido llamado TRACK MATTE

            En la capa seleccionada seleccionamos en la ventana Rastreador, Editar destino y cuando se abra la ventanita en la parte de capa elegiremos “track matte” y le daremos a aplicar en X e Y. Ocultamos la capa track matte. Con la capa seleccionada escogemos la herramienta del rectángulo para crear una máscara dentro de la capa y hacemos un recuadro en la cara. Desocultamos la capa. Seleccionamos la primera capa de FOOTAGE y elegimos opción de Alpha track matte. Si ocultamos la capa FOOTAGE veremos que desaparece todo menos el recuadro de la cara.


            Captura de pantalla 2016-08-29 a las 10.10.37
            Captura de pantalla 2016-08-29 a las 16.05.16
            Captura de pantalla 2016-08-29 a las 10.13.33

            En el menú Capa seleccionamos Estilos de Capa y Trazo a color blanco. En el punto del corte de las capas de FOOTAGE, seleccionando la segunda capa damos a:

            • Efecto – Corrección de color
              • Curvas
            Captura de pantalla 2016-08-29 a las 16.06.35

            Volvemos atrás en la línea de tiempo un frame y le damos al reloj para poner un keyframe. Volvemos al punto de inicio y nos vamos un frame más adelante ahora y bajamos la barra de curvas de forma que oscurezcamos el fondo.


            Línea de seguimiento

            Creamos una nueva capa de texto y la llamamos FRIEND OR FOE COMPUTING

            Creamos una nueva capa de sólido y lo llamamos HAZ. Y en esta capa aplicamos el efecto haz

            • Efecto – Generar
              • Haz
            Captura de pantalla 2016-08-30 a las 8.59.45

            En el panel de la izquierda de Controles y efectos: Haz
            – Duración 100%
            – Grosor de inicio 5
            – Grosor final 5
            – Suavizado 0
            – Color interior blanco
            – Color exterior blanco

            Un extremo lo llevamos al texto y el otro dentro del recuadro. Tenemos que hacer ahora que siga la misma posición que el track matte. En la capa del haz, sacamos una expresión en el Punto de inicio que será la siguiente:
            effect(*Haz*)(1)+thisComp.layer(“track matte”).transform.position.
            La espiral del haz la enlazamos con la posición de track matte. Veréis que se volverá loca la barra, pero lo que hay que hacer es ajustarlo manualmente, hacemos zoom y movemos los valores del Punto de inicio de la capa de Haz hasta la esquina inferior dejando que sobresalga un poco.

            Duplicamos la capa de track matte y la nueva capa generada la ponemos por encima de la capa de Haz, y en la capa de haz elegimos Alpha inverted track matte

            Captura de pantalla 2016-08-29 a las 11.07.19

            Barra de progreso

            Para la barra de progreso existe un preset que se puede descargar de la siguiente página http://cinemaspice.net/product/progress-bar/ con un coste de 4,99$ pero en mi caso yo la mía la hice siguiendo este tutorial en inglés How to make a Progress Bar

            Os dejo aquí el enlace con el vídeo del tutorial que hice Tutorial visión Terminator con After Effects CC

    Eventos y Modelos en Backbone.js

    $
    0
    0

    Eventos y Modelos en Backbone.js


    Índice de contenidos.


    1. Introducción

    En el anterior tutorial, ‘Introducción a Backbone.js’, hicimos una pequeña introducción sobre este potente framework javascript que nos permite desarrollar aplicaciones SPA (Single Page Application), permitiendo implementar de manera sencilla el patrón MVC (Model View Controller), en todas ellas.

    Pues bien, en este tutorial, como ya os comenté, daremos un paso más y nos adentraremos en cómo usar los eventos y modelos de Backbone.js en nuestra aplicación.


    2. Eventos

    Como os comenté en ‘Introducción a Backbone.js’, la forma que tenemos para comunicar las distintas partes de nuestra aplicación es mediante el lanzamiento de eventos entre sí. Es decir, podemos hacer que una vista se suscriba a determinados eventos de un modelo para que cuando éste cambie y lance dichos eventos, la vista renderice ese cambio de alguna manera.

    En Backbone, los eventos son un módulo más dentro de la librería. En nuestra aplicación, para dar a un objeto la habilidad de poder lanzar un evento que sea escuchado por el resto de componentes, tendremos que extender la funcionalidad de dicho objeto con la clase Backbone.Events:

    var testObject = {};
    	_.extend(testObject, Backbone.Events);
    Función ‘trigger’

    A partir de este momento nuestro objeto podrá lanzar eventos en el contexto de nuestra aplicación que serán escuchados por todos los componentes que se encuentren suscritos al mismo. Para ello usaremos la función ‘trigger’. Esta función recibe por parámetro el nombre del evento y los argumentos que queramos enviar al callback que se ejecutará cuando se lance dicho evento:

    var params = 'estoy lanzando un evento'
    	testObject.trigger('test:fire:event', params);

    Por convención, y para diferenciar los eventos de una aplicación, en los nombres de los eventos usaremos los dos puntos (:), en el nombrado de los mismos (en el ejemplo anterior: ‘test:fire:event’)

    Función ‘on’

    Para que el resto de componentes de la aplicación, que necesiten escuchar el evento lanzado, puedan reaccionar al evento, será necesario que se suscriban a dicho evento. Para ello usaremos la función ‘on’. Esta función recibe por parámetro el nombre del evento que se escuchará y la callback que se ejecutará cuando el evento se lance:

    var listener = {};
    	_.extend(listener, Backbone.Events);
    	listener.on('test:fire:event', function(data) {
    		console.log(data)
    	});
    Función ‘listenTo’

    La particularidad que tiene la función anterior es que el evento es lanzado a toda la aplicación y todos los componentes de dicha aplicación serán capaces de escuchar dicho evento. Pero puede algún componente sólo quiera escuchar un evento determinado. Para este caso usaremos la función ‘listenTo’. Esta función permite escuchar eventos de un determinado objeto. Recibe por parámetro la instancia del objeto a escuchar, el nombre del evento y el callback a ejecutar cuando el evento se lance:

    var listener = {};
    	_.extend(listener, Backbone.Events);
    	listener.listenTo(testObject, 'test:fire:event', function(data) {
    		console.log(data)
    	});

    3. Modelos

    Dentro de una aplicación javascript, los modelos son la parte más importante de la misma. Contienen y manejan los datos de la aplicación y se encargarán de gestionar la lógica de nuestra aplicación.

    Para crear un modelo, necesitamos extender de la clase Backbone.Model:

    var Alumno = Backbone.Model.extend({});
    Constructor

    Una vez creado nuestro modelo Alumno podemos crear instancias del modelo usando la palabra reservada ‘new’.

    var alumno = new Alumno({});

    Del mismo modo podemos crear una instancia pasándole por parámetro un hash con atributos y valores de los mismos que se van a dar de alta en el modelo:

    var alumno = new Alumno({
    		nombre: 'Ismael',
    		apellidos: 'Fernandez Molina',
    		dni: '77777777S',
    		edad: 30,
    		titulacion: 'Ingeniería Informática'
    	});
    defaults

    Para crear un modelo con atributos por defecto usaremos el hash ‘defaults’, el cual creará de forma automática los atributos indicados con los valores indicados cada vez que creemos una instancia del modelo.

    var Alumno = Backbone.Model.extend({
    		defaults: {
    			nombre: '',
    			apellidos: '',
    			dni: '',
    			edad: 0,
    			titulacion: ''
    		}
    	});
    
    	var alumno = new Alumno();
    Función ‘get’

    Para recuperar valores de los atributos de una instancia de un modelo, usaremos la función ‘get’. Para recuperar los valores pasaremos por parámetro una cadena con el nombre del atributo:

    var alumno = new Alumno({
    	    nombre: 'Ismael',
    	    apellidos: 'Fernandez Molina',
    	    dni: '77777777S',
    	    edad: 30,
    	    titulacion: 'Ingeniería Informática'
    	});
    
    	console.log(alumno.get('nombre'));
    	console.log(alumno.get('apellidos'));
    	console.log(alumno.get('edad'));
    	console.log(alumno.get('titulacion'));
    	console.log(alumno.get('dni'));
    Función ‘set’

    Para setear valores a un atributo del modelo usaremos la función ‘set’. Esta función recibe por parámetro el nombre del atributo y el valor que le vamos a dar:

    alumno.set('nombre', 'Manuel');
    	alumno.set('apellidos', 'García Montes');
    	alumno.set('edad', '22');

    Si necesitamos cambiar varios valores a la vez, esta función también está preparada para recibir un hash con todos los valores que queramos cambiar:

    alumno.set({
    		nombre: 'Manuel',
    		apellidos: 'Garcia Montes',
    		edad: 22
    	});
    Función ‘unset’

    Para eliminar atributos de un modelo usaremos la función ‘unset’. Esta función recibe por parámetro el nombre del atributo a eliminar del modelo:

    var alumno = new Alumno({
    	    nombre: 'Ismael',
    	    apellidos: 'Fernandez Molina',
    	    dni: '77777777S',
    	    edad: 30,
    	    titulacion: 'Ingeniería Informática'
    	});
    
    	alumno.unset('titulacion');
    	alumno.unset('edad');
    Atributo ‘cid’

    El atributo ‘cid’ es una cadena auto-generada por Backbone que identifica cada una de las instancias de los modelos que se van a creando en nuestra aplicación. No es aconsejable usar este atributo como identificador del modelo. Será necesario que creemos nuestro propio identificador para gestionar nuestras entidades para no tener problemas con el ‘cid’:

    var alumno = new Alumno({
    		nombre: 'Ismael',
    		apellidos: 'Fernandez Molina',
    		dni: '77777777S',
    		edad: 30,
    		titulacion: 'Ingeniería Informática'
    	}),
    	alumno2 = new Alumno({
    		nombre: 'Manuel',
    		apellidos: 'Garcia Montes',
    		dni: '77777777S',
    		edad: 30,
    		titulacion: 'Ingeniería Informática'
    	});
    
    	console.log(alumno.cid);
    	console.log(alumno2.cid);
    Atributo ‘id’

    Para definir el identificador del modelo setearemos el atributo ‘id’ el cual será usado como identificador único del modelo y usado para crear las URLs de persistencia con el servidor.

    var alumno = new Alumno({
    	    nombre: 'Ismael',
    	    apellidos: 'Fernandez Molina',
    	    dni: '77777777S',
    	    edad: 30,
    	    titulacion: 'Ingeniería Informática'
    	});
    
    	alumno.set('id', '984651');
    Atributo ‘idAttribute’

    Como acabamos de ver, Backbone usará el atributo ‘id’ como identificador del modelo si lo definimos. Si la comunicación con el backend es directa y el identificador del modelo en el backend no se llama ‘id’, podemos indicar a Backbone que use otro atributo como identificador. Para ello usaremos el atributo ‘idAttribute’:

    var Alumno = Backbone.Model.extend({
        idAttribute: 'codAlumno',
        defaults: {
    	   nombre: '',
    	   apellidos: '',
    	   dni: '',
    	   edad: 0,
    	   titulacion: ''
        }
    });

    4. Sincronización con el backend

    Los modelos de Backbone vienen preparados para dar soporte a la persistencia de datos. Ofrece una serie de funciones que nos serán muy útiles a la hora almacenar los datos y, de la misma forma, nos ahorrará tiempo ya que no tendremos que desarrollar de forma manual las llamadas a los backend’s.

    Backbone.sync

    Backbone nos proporciona una función que nos permite interaccionar con los backends para persistir o recuperar datos de modelos. Dicha función es Backbone.sync. Esta función recibe por parámetro el método que se va a ejecutar (“create”, “read”, “update”, “delete”), el modelo en cuestión y parámetros opcionales como los callbacks cuando la función ha funcionado correctamente o ha fallado.

    El funcionamiento de Backbone.sync es el siguiente: cuando lanzamos una llamada al backend con Backbone.sync, ésta coge todos los atributos del modelo, convierte los datos en un json y lanza una petición HTTP indicando que los datos que van a viajar son de tipo json (content-type: application/json). En función de la respuesta del backend (si devuelve datos o no), el modelo se actualizará con los datos que se devuelvan o no.

    Como ya hemos indicado anteriormente, Backbone buscará el identificador del modelo para construir las llamadas (REST), a los backends. De esta forma tendremos lo siguiente:

    metodo:’read’ –> verbo:GET –> url:’/modelName[/id]’

    metodo:’create’ –> verbo:POST –> url:’/modelName’

    metodo:’update’ –> verbo:PUT –> url:’/modelName/id’

    metodo:’patch’ –> verbo:PATCH –> url:’/modelName/id’

    metodo:’delete’ –> verbo:DELETE –> url:’/modelName/id’

    Función ‘fetch’

    Esta función llama internamente a Backbone.sync para recuperar los datos del modelo procedentes del backend.

    var alumno = new Alumno({
    	  id: 1
    	  nombre: '',
    	  apellidos: '',
    	  dni: '',
    	  edad: 0,
    	  titulacion: ''
    	});
    
    	alumno.fetch();
    Función ‘save’

    Esta función llama internamente a Backbone.sync para almacenar los datos del modelo en el backend (ya sea en el servidor, fichero, etc.). Puede recibir por parámetro un hash con los datos del modelo que se van a modificar. Aunque luego, internamente enviará el hash completo con los datos del modelo. Si el modelo es un modelo ya existente, internamente se lanzará una actualización (method: update –> PUT), de lo contrario, si es nuevo, se lanzará un alta (method: create –> POST).

    var alumno = new Alumno({
    	  id: 1
    	  nombre: 'Ismael',
    	  apellidos: 'Fernandez Molina',
    	  dni: '77777777S',
    	  edad: 30,
    	  titulacion: 'Ingeniería Informática'
    	});
    
    	alumno.save({
    	  nombre: 'Manuel',
    	  apellidos: 'Garcia Montes'
    	});

    Esta función, cada vez que es llamada, realiza una llamada al método ‘validate’ del modelo, si éste lo tiene definido, para comprobar si los datos del modelo son correctos y si se puede seguir con el guardado de datos. En el caso de que el método ‘validate’ indicase lo contrario, la función ‘save’ se abortaría y se devolvería un callback con el error. El método ‘validate’ recibe por parámetro un objeto con los atributos del modelo.

    var Alumno = Backbone.Model.extend({
    	  defaults: {
    	   nombre: '',
    	   apellidos: '',
    	   dni: '',
    	   edad: 0,
    	   titulacion: ''
    	  },
    	  validate: function(attributes) {
    	    if (attributes.id <= 0) {
    	      return 'El id del alumno no es válido';
    	    }
    	  }
    	});
    Función ‘destroy’

    Esta función elimina un modelo del backend. Al igual que las anteriores, delega la responsabilidad a Backbone.sync, el cual lo traducirá a una petición HTTP de tipo DELETE.

    var alumno = new Alumno({
      id: 1
      nombre: 'Ismael',
      apellidos: 'Fernandez Molina',
      dni: '77777777S',
      edad: 30,
      titulacion: 'Ingeniería Informática'
    });
    
    alumno.destroy();

    5. Eventos lanzados por defecto

    Al principio de este tutorial hemos hablado sobre cómo podemos hacer que determinadas partes de nuestra aplicación escuchen los eventos que los modelos pueden lanzar. Los ejemplos que he mostrado son para los casos en los que nosotros programemos de forma manual ese lanzamiento de evento. De los que no hemos hablado son de los eventos que los modelos de Backbone ya lanzan por defecto cada vez que algo ocurre con los datos que éstos manejan.

    Aquí os dejo la lista de eventos que se lanzan por defecto:

    add — cuando un modelo es añadido a una colección (en el siguiente tutorial hablaremos sobre las colecciones) remove — cuando un modelo se elimina de una colección change — cada vez que un atributo de un modelo se actualiza change:[attribute] — cada vez que un atributo específico del modelo ([atribute]), se actualiza destroy — cuando un modelo se ha eliminado request — cuando un modelo inicia una petición hacia el backend sync — cuando la llamada que un modelo hace hacia el backend se ha ejecutado de forma satisfactoria error — cuando la llamada que un modelo hace hacia el backend ha fallado invalid — cuando la validación de un modelo ha fallado all — este evento se lanza cada vez que cualquier evento es lanzado en nuestra aplicación

    Llegado a este punto os puedo decir que los modelos de Backbone contienen muchas más funciones relacionadas con el manejo de los datos. Aquí os he detallado algunas de las principales y que más vais a usar a la hora de desarrollar una aplicación. Si queréis ampliar vuestro conocimiento sobre las funciones que nos proporcionan los modelos de Backbone podéis echarle un ojo a la documentación oficial de Backbone.js


    6. Conclusiones

    Como podéis ver, Backbone nos proporciona una multitud de funciones para el manejo de modelos en nuestra aplicación. Como hemos comentado, los modelos serán el core de nuestra aplicación y mediante la multitud de funciones y utilidades que ya nos proporciona este potente framework seremos capaces de gestionar la lógica de la aplicación de manera sencilla. Es cuestión de práctica el controlar su funcionamiento.

    Pero no solo reside aquí su potencia. Quizá el punto más interesante de este framework es la sencillez con la que somos capaces de comunicar nuestra aplicación con los backends gracias Backbone.sync.

    Poco a poco iremos ampliando la funcionalidad de este framework para que finalmente podamos dejaros una pequeña aplicación aplicando todo lo aprendido.

    Unas pistas para el problema de concurrencia

    $
    0
    0

    En el último artículo, presentamos un problema de concurrencia para que lo resolvieses. Aquí damos algunas pistas para ayudar a que averigües qué sucede.

    Éste artículo es una traducción al castellano de la entrada original publicada, en inglés, por Dr. Heinz Kabutz en su número 241b de The Javatm Specialists’ Newsletter. Puedes consultar el texto original en Javaspecialists’ Newsletter #241:b Concurrency Puzzle Useful Hints

    Este artículo se publica traducido en adictos, con permiso del autor, por David Gómez García, (@dgomezg) consultor tecnológico en Autentia, colaborador de JavaSpecialists y instructor certificado para impartir los cursos de JavaSpecialists.

    Un problema de concurrencia – Unas pistas útiles.

    Muchas gracias a todos los que ya me han enviado por correo su solución al problema de la semana pasada. La mayoría de las respuestas eran correctas en teoría, pero incorrectas en la práctica :-) . Por mi experiencia es mejor aprender practicando, más que observando a otro. Por eso, sacarás más beneficio intentando resolverlo que leyendo mi solución. Así que, si aún no lo has intentado o te has quedado bloqueado en algún punto, aquí te dejo algunas pistas útiles:

    1. Podemos discutir la corrección utilizando el Java Memory Model (JMM). No obstante, la mayoría de los problemas de concurrencia que se pueden presentar con happens-before, early-writes, visibilidad, etc… son muy difíciles de reproducir. Seguramente nos sería difícil escribir un test que fallase de forma consistente con este. Esa es la primera pista.
    2. La segunda pista pasa por no creer nunca lo que te dicen tus clientes que es el problema. La explicación con System.arraycopy() es claramente una “pista falsa”. Para ser justos, Jack me lo envió como una posible explicación. No obstante, no miré al código de System.arraycopy() porque realmente no creía que la razón del fallo fuese a estar allí. Así que puedes ignorar el System.arraycopy(). Puedes comprobar que si arrancas con un array mayor de 1000, también falla.
    3. Siempre que tratamos de resolver problemas de concurrencia, debemos ser capaces de reproducir el error primero. Esto puede implicar que necesitemos buscar otro hardware que muestre el problema (es lo que yo hice). Una vez que lo ves producirse, cambia el código poco a poco comprobando si todavía se reproduce.
    4. Última pista. La solución a este problema es increíblemente simple. De veras, cualquier desarrollador Java puede solucionarlo, no sólo los gurús de la concurrencia. Hay un pequeño efecto colateral que está prohibido con Swift 3 y que es el que causa la condición de carrera. No hay más pistas 😉

    También sugerí que utilizases StampedLock para escribir este código de forma correcta. Admito que esto es un poquito más difícil que resolver el problema. StampedLock tiene tres formas base de utilizar add(), remove() y get() según su JavaDoc. Cuando lo tengas, por favor, envíamelo por correo y tendrás tu oportunidad de contribuir a nuestra solución y poner tu nombre en los créditos.

    Saludos

    Heinz.

    Comentando el libro ‘Ágilmente’ de Estanislao Bachrach

    $
    0
    0

    Vuelvo a tratar el tema que comencé con mi anterior entrada Comentando el libro Creatividad S.A., la creatividad.

    Las preguntas que nos puede ayudar a resolver el libro Ágilmente, Aprende cómo funciona tu cerebro para potenciar tu creatividad y vivir mejor de Estanislao Bachrach, son las siguientes:

    • ¿De dónde surgen las ideas?
    • ¿Cualquiera tiene la capacidad de ser creativo?
    • ¿Qué podemos hacer para mejorar nuestras capacidades creativas?
    • ¿Cuáles son las barreras a la creatividad?

    Este libro, desde mi punto de vista, es altamente recomendable. Estos son algunos de los motivos que os puedo dar para animaros:

    • Nos proporciona una definición de creatividad que nos sitúa en la dirección correcta para empezar a mejorar nuestras habilidades en materia de generación de ideas
    • Ayuda a reconocer y superar las barreras que pueden dificultar la actividad de una mente creativa
    • Está plagado de técnicas que podemos utilizar para desarrollar y mejorar nuestra creatividad
    • Nos sugiere una forma de afrontar la vida basada en la curiosidad y disfrutando de procesos divertidos
    • El conocimiento y manejo de las emociones ocupa un lugar importante en el libro
    • Se presentan algunas propuestas de relajación y meditación que nos faciliten la calma mental necesaria para afrontar los desafíos creativos
    • Es realmente ameno, incluso explicando las bases psicológicas y neurológicas que apoyan las ideas aportadas

    El objetivo principal del libro es ayudar al lector a conocer el funcionamiento del cerebro en materia de generación de ideas, para luego llevar a cabo una serie de técnicas y prácticas que le permitan desarrollar y mejorar sus habilidades creativas. Por tanto, cualquiera que tenga curiosidad por conocer algunos de los últimos descubrimientos sobre la mente del ser humano, aprender divertidas técnicas para crear nuevas ideas e incluso mejorar sus respuestas emocionales a eventos inesperados, debe leer este libro.

    No va a ser tarea fácil, pero a continuación os dejo el resumen de algunas de las ideas que considero más importantes del libro y que más me han llamado la atención.

    ¿Qué es la creatividad?

    La creatividad se puede definir de distintas maneras, algunas de las definiciones aportadas en el libro son:

    • Actividad mental por la que se produce una revelación en el cerebro dando como resultado una idea
    • Mezcla de conceptos, experiencias, información, datos o conocimiento, aparentemente no relacionado, registrado en algún lugar de la memoria

    Esta segunda definición es probablemente la más interesante desde el punto de vista práctico, ya que nos da una primera pista de lo que tenemos que hacer si queremos producir más ideas. De hecho me recuerda a otra definición de creatividad que leí hace poco del psicólogo Sarnoff A. Mednick, que dice algo así como que la creatividad es memoria asociativa que trabaja excepcionalmente bien. En resumen, para ser creativos, debemos de ser capaces de asociar conceptos que ya conocemos de alguna manera novedosa.

    Pensamiento productivo vs pensamiento reproductivo

    En nuestro cerebro, cómo ya supondréis, se producen muchas contradicciones, una de ellas surge al chocar las siguientes órdenes:

    • Conserva energía
    • Esfuérzate en descubrir cosas nuevas

    Y ninguna es mala, de hecho, la primera tiene su explicación en el ámbito de supervivencia, ahorra energía para estar preparado ante cualquier imprevisto. Y la segunda, es la que nos ha permitido evolucionar como especie. Lo que ocurre es que esta, requiere esfuerzo. Una de las ideas fundamentales de Ágilmente, es que nos esforcemos para enviar con más frecuencia esta orden al cerebro. Ya que es gracias a la que conseguiremos romper los patrones mentales predominantes y generar nuevas asociaciones que se traduzcan en una idea creativa.

    Romper patrones

    Los patrones mentales son conexiones entre neuronas muy útiles para realizar tareas diarias como conducir, cepillarnos los dientes, etc, sin esfuerzo. Imaginaos qué cada vez que hiciéramos estas cosas tuviéramos que aprenderlas de nuevo.

    Pero no todo es bueno, ya que si siempre hacemos uso de estos patrones que hemos ido construyendo a medida que crecemos, se fortalecerán más y más, y se convierte en una tarea complicado el generar nuevas asociaciones, es decir, nuevos caminos entre neuronas. Y esto como hemos visto requiere esfuerzo.

    No voy a enumerar la enorme cantidad de técnicas y consejos para crear nuevos patrones de pensamiento que Estanislao Bachrach plasma en su libro. Lo importante de la mayoría de las técnicas es que juegan con la mezcla de conceptos a priori no relacionados y de los que tenemos que sacar un nuevo concepto novedoso. Por ejemplo, ventana y pie, los relacionamos y sale algo como una ventana con una base en la que podamos apoyar los pies y airearlos.

    Como os podéis imaginar, muchos de los conceptos e ideas surgidas serán malas o no tendrán sentido implementarlas, pero lo importante es aprender a generar muchas ideas porque aumentaremos las probabilidades de que alguna de ellas sea buena.

    Percepción

    Como nos señala el autor, la percepción es la función del cerebro que elabora la información procedente del entorno y construye la realidad, NUESTRA realidad. Estamos influidos por nuestras percepciones, que como se ha demostrado no son demasiado fiables, ya que en realidad procesamos muy poco de la información recibida y la completamos con lo que ya sabemos (o creemos saber).

    En el libro, se habla de un concepto que probablemente reconoceréis, el punto ciego del experto. Cuando sabemos mucho sobre alguna materia, nos podemos ver condicionados por nuestro propio conocimiento, ya que nos costará mucho más encontrar soluciones creativas a algún problema relacionado con dicha materia.

    Por este motivo, es importante desarrollar nuestra capacidad para ver las cosas desde otros puntos de vista. Tarea para nada fácil pero que merece la pena el esfuerzo. Además, hay también muchas formas divertidas para desarrollar la percepción como por ejemplo viajar.

    Emociones

    El autor dedica un capítulo completo a las emociones, y son nombradas en muchas ocasiones a lo largo del libro, por algo será…

    A mi siempre me ha resultado muy interesante este tema, por lo que aprender cosas nuevas y reforzar mi conocimiento sobre él es algo que agradezco.

    No voy a ponerme a explicar aquí el papel que ocupan las emociones en nuestra mente y por tanto en nuestro comportamiento. Pero como muchos de vosotros sabréis, los estímulos emocionales rigen nuestras acciones y pensamientos ante ciertas situaciones como por ejemplo, alejarse ante un peligro.

    Las emociones nos asaltan constantemente y tienen un enorme poder en lo que pensamos, hasta el punto de llegar a tomar el control de las situaciones. Por tanto, como para muchas otras cosas, si queremos esforzarnos en desarrollar una mente capaz de generar muchas ideas, debemos aprender a identificar y regular las emociones.

    En Ágilmente se nos aconseja sobre la forma de conseguirlo, expresándolas, reformulándolas, transformándolas, en fin… Formas hay muchas, lo importante es que cada uno encuentre la suya para así conseguir ese preciado y complicado equilibrio entre emoción y razón.

    Proceso creativo

    Las diferentes etapas que componen un proceso creativo según el autor, son las siguientes:

    • Preparación. Sumergirse en el problema.
    • Incubación. Las ideas comienzan a agitarse por debajo del umbral de la consciencia. Posiblemente la etapa más creativa, ya que las ideas no expuestas bajo la lupa de la lógica.
    • Revelación o insight. Puede ocurrir en cualquier momento, ¡hemos tenido una idea!
    • Evaluación. ¿La idea es realmente buena?
    • Elaboración. Hacer madurar la idea, convencer a los demás. Requiere salir de la zona de confort, expones a tu idea recién nacida al mundo real.

    Estanislao Bachrach indica que estas etapas no son secuenciales, pueden seguir otro orden y repetirse.

    Relajación

    Si queremos una mente sana y eficiente capaz de generar muchas y buenas ideas, tenemos que aprender a relajarnos. No podemos permitir que los pensamientos descontrolados y las emociones negativas llenen de ruido nuestra cabeza. Las propuestas, como os podéis imaginar son:

    • Meditación
    • Yoga
    • Ejercicio
    • Amigos y familia
    • Descanso

    Lo importante es lo que se señala en el libro, tener una mente relajada promueve asociaciones nuevas, el cerebro tendrá más facilidad para crear nuevos caminos entre neuronas, ya que se disminuye la actividad de los patrones predominantes.

    Hasta aquí mi intento de resumir este interesantísimo libro, mi recomendación es lo que leáis. Aprenderéis mucho, no sólo a generar ideas, sino del funcionamiento del cerebro y por tanto, sobre vosotros mismos.


    Cómpralo en Amazon

    Ahora toca dar mi opinión, ¿lo que se dice en el libro funciona? Os diré que he intentado poner en práctica alguna de las divertidas técnicas sugeridas en él, teniendo como base el conocimiento que también aporta para así entender lo que estaba haciendo. Lo primero que tengo que decir es que son muy divertidas, tomároslas como un juego, jugad con otras personas. Yo aprovechaba los paseos veraniegos con mi chica y mi perra para ponerlos en práctica.

    Realmente te vas dando cuenta que cada vez tienes una mayor facilidad para que se te ocurran ideas, por supuesto algunas son una chorrada, pero por lo menos te ríes. Otra cosa que he notado, es que te ayudan a ser más consciente del entorno y de tus propios pensamientos, y por tanto, te sitúan en el momento presente. Esto facilita la búsqueda de asociaciones no habituales y además te produce una sensación de bienestar muy agradable.

    En Autentia proporcionamos soporte a la implantación corporativa de metodologías ágiles ayudando a la transformación digital de grandes organizaciones. Te invito a que te informes sobre los servicios profesionales de Autentia y el soporte que podemos proporcionar a tu empresa en el camino hacia el agilismo.

    Pues poco más, sed felices y ¡nos vemos pronto!

    Equipos de desarrollo con SAFe: Equipos Ágiles

    $
    0
    0

    Índice de contenidos


    1. Introducción
    2. El Nivel de Equipo y sus Roles
    3. Incrementos en el Programa y las Iteraciones
    4. Historias de Usuario y el Team Backlog
    5. Conclusiones
    6. Referencias

    1. Introducción

    Con el objetivo de darle continuidad al artículo de Introducción a SAFe, iré publicando una serie de apartados que sirvan de guía para la adopción de está metodología como marco de trabajo para el escalado del agilismo en grandes organizaciones.

    Dado que el objetivo de está metodología es aumentar la productividad en el desarrollo de software a todos los niveles de una organización, comenzaré haciendo un análisis del Nivel de Equipo como base para el modelo que describe las actividades de los equipos de desarrollo en organizaciones ágiles.

    Nivel de Equipo

    Figura 1. Nivel de Equipo. Recuperado de www.scaledagileframework.com



    2. El Nivel de Equipo y sus Roles

    Según la Big Picture de SAFe, los equipos de desarrollo están enmarcados en un nivel independiente llamado Nivel de Equipo. En este nivel se sincronizan todas las iteraciones en ciclos de trabajo común y con longitud fija, en lo que se denomina el Agile Release Train (ART).

    Bajo este marco de trabajo, los equipos son concebidos para ser autogestionados y hacerse responsables de definir, construir y probar cada una de sus historias de usuario. Como garantías de calidad se promueve el uso de las buenas prácticas de ScrumXP o Team Kanban como marcos de trabajo para la de gestión de las actividades de los equipos.

    Como parte de la definición de ScrumXP, se definen los siguientes roles como parte del estándar de las guías SAFe:

    • El Scrum Master, es el encargado de ayudar a los equipos de desarrollo a cumplir sus objetivos de negocio. El Scrum Master es el líder de servicio y encargado de fomentar la autogestión y facilitar el uso de la metodología.
    • El Product Owner, sirve como cliente proxy y es responsable de trabajar con el negocio en la definición y priorización de las historias de usuario. Entre sus funciones con el equipo se encuentra la de procurar la entrega de valor con integridad técnica.
    • Finalmente los Agile Teams son pequeño grupos de individuos (de entre 5 y 9 personas) que tienen las habilidades técnicas necesarias para definir, construir y probar incrementos de valor en períodos acotados.
    Adicional a los roles mencionado, el Nivel de Programa incluyen algunos otros roles de responsabilidad transversal que facilitan las actividades de desarrollo y garantizan la entrega de valor en sistemas probados. Estos roles se comentarán con detalles en un artículo dedicado a este nivel.

    3. Incrementos en el Programa y las Iteraciones

    Como lo comenté anteriormente los equipos de desarrollo se sincronizan en ciclos de trabajo comunes y de longitud fija. El objetivo de esta coordinación es lograr Incrementos en el Programa (PI, por sus siglas en inglés) bajo un calendario preestablecido.

    Cada PI consiste en un conjunto de iteraciones que comienzan con la participación de los equipos involucrados en una reunión de planificación (PI Planning) donde se determinan los objetivos que sirven de guía durante el ciclo de trabajo del PI. La duración de cada iteración está acotada a dos semanas y tiene el objetivo de proveer de nuevas funcionalidades al sistema, bajo un patrón de trabajo repetitivo.

    En la dinámica también se incluye un proceso de pruebas al final de cada iteración, una verificación para demostrar las funcionalidades liberadas y una reunión retrospectiva donde los equipos discuten sus prácticas e identifican puntos de mejora.

    Ciclo de las iteraciones con SAFe

    Figura 2. Ciclo de las iteraciones con SAFe


    SAFe divide los ciclos de desarrollo en un conjunto de iteraciones hasta alcanzar un PI, aunque no lo imponen como una regla explícita la duración de estos ciclos se recomienda que oscile entre las 8 y 12 semanas.

    4. Historias de Usuario y el Team Backlog

    El Team Backlog representa la colección de todas las tareas que un equipo tiene que hacer para avanzar en su porción del sistema acotado por el PI. Es durante la planificación del PI que se le asigna a los equipos las historias de usuario que usan para entregar valor, y el Product Owner es quien tiene la autoridad para crearlas y aceptarlas en su Team Backlog. Puede contener usuarios y facilitadores, la mayoría de los cuales son identificados durante está fase de planificación.

    En la siguiente imagen se refleja las principales fuentes que alimentan las historias del Team Backlog.
    FuentesdelbacklogSAFe

    Figura 3. Fuentes del Team Backlog


    Como se puede ver en la imagen, el Team Backlog puede verse afectado con ciertas historias que contengan dependencia o incluyan soporte de agentes externo.

    La identificación, priorización, planificación, elaboración, implementación, prueba y aceptación de las historias, son los procesos asociados a éstas que se gestionan en el Nivel de Equipo.

    5. Conclusiones

    • Los equipos de desarrollo ágil son la base sobre las que se fundamenta SAFe.
    • Cada equipo es responsable de definir, construir y probar las historias de usuario de su Backlog en una serie de iteraciones de longitud fija.
    • Se fomenta la agilidad y la mejora continua en cada uno de los ciclos de trabajo.

    En Autentia proporcionamos soporte a la implantación corporativa de metodologías ágiles ayudando a la transformación digital de grandes organizaciones. Te invito a que te informes sobre los servicios profesionales de Autentia y el soporte que podemos proporcionar a tu empresa en la implantación de frameworks de escalado de agile como SAFe y LESS.


    6. Referencias

    Viewing all 989 articles
    Browse latest View live