Weblogs Código

Blog Bitix

Novedades de Java 13

octubre 22, 2019 05:00

Java

Continuando las mejoras incrementales cada seis meses el 17 de septiembre se publico Java 13. Java 13 incorpora algunas nuevas características interesantes que mejoran un facilitan la lectura del código, entre las más destacadas están los bloques de texto y las expresiones switch mejoradas.

Casi coincidiendo con la publicación de Java 13 se publicado [Jakarta EE][jakarta] 8 que únicamente tiene como novedad que su propiedad ha pasado a estar baja la fundación Eclipse, es totalmente compatible con Java EE 8 y sus últimas mejoras, las novedades vendrán en versiones posteriores de Jakarta EE en las que se dará importancia a la tendencia de las aplicaciones para su funcionamiento en entornos orientados a la nube. Casi al mismo tiempo se ha publicado JavaFX 13 ya fuera del JDK en onde puede seguir su propio ciclo de publicaciones independiente del JDK.

Bloques de texto

Para definir una cadena de caracteres que tuviese varias lineas en Java había que emplear concatenación de cadenas, si esa cadena contiene el caracter comilla doble de inicio de cadena había que escaparlo, si esa cadena contenía saltos de línea había que emplear el caracter de escape de salto de línea \n. El resultado es una cadena con problemas de legibilidad por los caracteres de escape que incluye en el código fuente del lenguaje. Esto podría se al definir una cadena de texto que tuviese elementos HTML, JSON, sentencias SQL o expresiones regulares.

1
2
3
4
5
String html = "<html>\n" +
" <body>\n" +
" <p class=\"text\">Hello, Escapes</p>\n" +
" </body>\n" +
"</html>\n";

Con los bloques de texto se emplean una triple comilla doble para la apertura y cierre de la cadena.

1
2
3
4
5
6
String html = """
 <html>
 <body>
 <p class="text">Hello, Text Blocks</p>
 </body>
 </html>""";

Como ayuda a las cadenas de texto en la clase String se han añadido varios métodos para eliminar la indentación (String::stripIndent), traducir los caracteres secuencia de escape (String::translateEscapes) y formatear una cadena usando un método de instancia (String::formatted).

Expresiones switch mejoradas

En las novedades de Java 12 se añadió la posibilidad de los switch fueran expresiones que retornan un valor en vez de sentencias y se evita el uso de la palabra reservada break.

1
2
3
4
5
6
String numericString = switch(integer) {
case 0 -> "zero";
case 1, 3, 5, 7, 9 -> "odd";
case 2, 4, 6, 8, 10 -> "even";
default -> "N/A";
};

En Java 13 en vez únicamente el valor a retornar se permite crear bloques de sentencias para cada rama case y retornar el valor con la palabra reservada yield. En los bloques de sentencias puede haber algún cálculo más complejo que directamente retornar el valor deseado.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
String numericString = switch(integer) {
case 0 -> {
String value = calculateZero();
yield value;
} ;
case 1, 3, 5, 7, 9 -> {
String value = calculateOdd();
yield value;
};
case 2, 4, 6, 8, 10 -> {
String value = calculateEven();
yield value;
};
default -> {
String value = calculateDefault();
yield value;
};
};

Otras características

Las las otras tres características destacadas Dynamic CDS Archives, ZGC: Uncommit Unused Memory para la mejora del recolector de basura y Reimplement the Legacy Socket API reescribiendo el código para los sockets en lenguaje Java son cambios internos que afectan a la plataforma Java pero no al lenguaje.

» Leer más, comentarios, etc...

Fixed Buffer

Entity Framework Core 3.0: ¿qué novedades nos trae?

octubre 22, 2019 08:00

La imagen muestra el logo de Entity Framework Core

Hace unas semanas desde que se hizo pública la versión 3.0 de .Net Core y nos ha traído muchas novedades: C# 8, soporte ampliado en Windows, mejoras de rendimiento, Worker Services… Y como no, también nos trae una nueva versión de Entity Framework Core.

Son muchas las novedades que nos trae esta nueva release, que nos aportan mejoras de rendimiento, pero también cambios en el diseño. En esta entrada vamos a ver algunas de las características más importantes de esta nueva versión, aunque te recomiendo que le eches un ojo a la lista completa de cambios que trae Entity Framework Core 3.0 (y también a la lista de breaking changes).

Instrucción SQL única por consulta LINQ

Se ha mejorado el motor de generación de sentencias SQL, anteriormente, consultas que hiciésemos con varias tablas, podían llevar a ejecutar varias consultas a la base de datos en vez de una sola (que es lo que esperamos al utilizarlo). Entity Framework Core 3.0 garantiza que solo se va a generar una única consulta que lanzar a la base de datos, y en caso de no poder traducirse a una única consulta, nos lanzara una excepción que nos lo va a indicar para que podamos refactorizar el código.

Restricción de la evaluación en cliente

En versiones anteriores, si una consulta no se podía traducir a SQL, se realizaba lo que se conoce como evaluación en cliente. Esto significa que se iba a lanzar a la base de datos una consulta con los máximos filtros posibles aplicados, y los que no se pueden traducir, se aplicaban en el propio cliente, a costa de traerse los datos en bruto y procesarlos en nuestra aplicación. Imagina este código (obtenido de la documentación oficial):

public static string StandardizeUrl(string url)
{
    url = url.ToLower();
    if (!url.StartsWith("http://"))
    {
        url = string.Concat("http://", url);
    }
    return url;
}

var blogs = context.Blogs
    .Where(blog => blog.Date > DateTime.Now.AddYears(-1) StandardizeUrl(blog.Url).Contains("dotnet"))
    .ToList();

Estamos utilizando una condición que la base de datos no puede ejecutar, por lo que el comportamiento va a ser:

  1. Hacemos una consulta que nos devuelve toda la tabla filtrada por fecha.
  2. Filtramos en memoria toda la tabla para aplicar nuestra condición personalizada.
  3. Generamos una lista con los resultados filtrados

Aunque esto a veces puede ser útil, si la tabla se hace grande va a ser una gran perdida de rendimiento. Por defecto, en versiones anteriores se permitía la consulta y se indicaba un warning. Este comportamiento por defecto a cambiado en Entity Framework Core 3.0, ahora va a lanzar una excepción que nos lo va a indicar. Si queremos hacer la evaluación en cliente, tenemos que hacerlo de forma explicita:

var blogs = context.Blogs
    .Where(blog => blog.Date > DateTime.Now.AddYears(-1))
    .AsEnumerable() //Cambiamos a Linq de objetos
    .Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
    .ToList();

Compatibilidad con C# 8

La nueva versión de C# nos trae muchas mejoras y nuevas APIs, y entre ellas IAsyncEnumerable, lo que junto a «await foreach», nos va a permitir mejorar la velocidad a la que se ejecutan las consultas, ya que vamos a ir procesando los datos a medida que están disponibles. Gracias a C# en Entity Framework Core 3.0 podemos hacer algo como esto:

var orders = 
  from o in context.Orders
  where o.Status == OrderStatus.Pending
  select o;

//Cada nuevo nuevo dato obtenido los vamos a procesar inmediatamente
await foreach(var o in orders.AsAsyncEnumerable())
{
    Process(o);
} 

El tooling de Entity Framework Core 3.0 ya no forma parte de .Net Core 3.0

Un cambio de diseño importante es que .Net Core ya no trae integrado el set de herramientas para trabajar con Entity Framework Core. Es decir, vamos a necesitar instalar a parte el set de herramientas si realmente nos interesa usarlo. Esto lo podemos hacer de manera local con el archivo de manifiesto de herramientas o de manera global con el comando:

dotnet tool install --global dotnet-ef

Esta desarrollado para .Net Standard 2.1

Esta nueva versión de Entity Framework Core, está desarrollado cumpliendo con .Net Standard 2.1, esto es lo que le permite tener grandes mejoras de rendimiento, pero limita las plataformas donde se puede utilizar, .Net Core 3.0 es compatible con .Net Standard 2.1, pero .Net Framework no es compatible, por lo qué si necesitas usarlo en .Net Framework, no vas a poder utilizar Entity Framework Core 3.0.

Y un largo etcétera…

La verdad es que no se limitan a esto los cambios que nos ofrece esta nueva versión. Yo he querido resaltar los que a mi parecer son los más importantes o necesarios tener en cuenta si vienes de trabajar con versiones anteriores, pero te recomiendo encarecidamente que le eches un ojo a las nuevas características y sobre todo, a la lista de cambios que no son retrocompatibles. Verás que esta es una nueva versión muy interesante y con muchas mejoras.

**La entrada Entity Framework Core 3.0: ¿qué novedades nos trae? se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Variable not found

Enumerables asíncronos en C# 8

octubre 22, 2019 06:15

.NET Core Hasta ahora, la generación o enumeración de secuencias era un proceso puramente síncrono. Por ejemplo, si queríamos recorrer un IEnumerable con un bucle foreach, cada uno de los elementos debía existir previamente en la colección o bien ser generado de forma síncrona.

Por ejemplo, en el siguiente código no teníamos una forma razonable de implementarlo si la obtención de cada uno de los valores retornados desde el método generador tuviera que ser asíncrona:
foreach (var i in GetNumbers())
{
Console.WriteLine(i);
}

IEnumerable<int> GetNumbers()
{
for (var i = 0; i < 1000_000_000; i++)
{
var a = i * 2; // <-- Esto es una operación síncrona,
yield return a; // ¿cómo haríamos si en lugar de esta operación síncrona
// necesitásemos hacer una llamada asíncrona para obtenerlo?
}
}
Aunque convertir el método GetNumbers() en asíncrono pudiera parecer una alternativa razonable, en realidad no lo es; de hecho, los resultados no llegarían al cliente hasta que hubiéramos generado todos los valores, por lo que sería peor que la primera opción en términos de rendimiento y ocupación de memoria:
foreach (var i in await GetNumbersAsync())
{
Console.WriteLine(i);
}

async Task<IEnumerable<int>> GetNumbersAsync()
{
var list = new List<int>();
for (var i = 0; i < 1000_000_000; i++)
{
var a = await Task.FromResult(i * 2); // <-- Aquí generamos los valores usando asincronía,
list.Add(a); // pero el consumidor seguirá esperando hasta
// que los hayamos generado todos.
}
return list; // <-- Aquí retornamos la colección completa
}
En este último caso la llamada a GetNumbersAsync() se ejecutaría de forma asíncrona, es decir, daríamos la oportunidad al hilo de ejecución actual de dedicarse a otros menesteres mientras la llamada es realizada, desde el punto de vista de su consumidor es a todos los efectos como si se tratara de un método síncrono.

Pues bien, aparte de características mainstream como la implementación por defecto en interfaces, los tipos referencia anulables, índices y rangos o muchas otras, en la última versión del framework y C# 8 se ha introducido el soporte para la generación y consumo de secuencias asíncronas.

En la práctica, esto implica que a partir de ahora se puede iterar sobre una enumeración en la que cada elemento puede ser obtenido de forma asíncrona. Para ello, se han introducido dos cambios en .NET y C#:
  • Primero, en lugar de IEnumerable<T>, los métodos o funciones generadoras deberán utilizar IAsyncEnumerable<T>. Básicamente es lo mismo que antes, pero indicamos que cada elemento de la secuencia se generará de forma asíncrona.
     
  • Segundo, para iterar sobre los elementos utilizaremos la construcción await foreach(), que indica que cada elemento se obtendrá de forma asíncrona y, por supuesto, sin esperar a tener materializada la colección completa.
El siguiente bloque de código muestra una versión actualizada del código con el que estamos trabajando en este post. Fijaos que los valores son retornados al consumidor utilizando el clásico yield conforme van siendo generados de forma asíncrona:
await foreach (var i in GetNumbers())
{
Console.WriteLine(i);
}

async IAsyncEnumerable<int> GetNumbers()
{
for (var i = 0; i < 1000_000_000; i++)
{
var a = await Task.FromResult(i * 2); // <-- Esto podría ser cualquier tipo
yield return a; // de operación asíncrona
}
}
Otra de las ventajas de utilizar IAsyncEnumerable es que en los métodos generadores podríamos utilizar tokens de cancelación, aunque para conseguirlo de forma correcta debemos hacer uso de dos particularidades:
  • Primero, en la llamada al método generador, debemos utilizar el extensor WithCancellation() para suministrarle el token de cancelación al que deberá atender para cancelar el streaming de valores.
  • Segundo, en la signatura del método generador, debemos añadir un parámetro de tipo CancellationToken para recibir el token de cancelación, decorándolo con el atributo [EnumeratorCancellation].
El siguiente código muestra un ejemplo de uso
public static async Task Main()
{
var token = new CancellationTokenSource(100); // Cancel after 100 ms
await foreach (var i in GetNumbers().WithCancellation(token.Token))
{
Console.WriteLine(i);
}
}

static async IAsyncEnumerable<int> GetNumbers(
[EnumeratorCancellation] CancellationToken token = default)
{
for (var i = 0; i < 1000_000_000 && !token.IsCancellationRequested; i++)
{
var a = await Task.FromResult(i * 2);
yield return a;
}
}

Y, ¿sirve esto para algo?

Sin duda, y probablemente cada vez más, puesto que casi todos los tipos de aplicación (web, desktop, móvil...) al final necesitan mejorar su capacidad de obtener datos de forma asíncrona desde cualquier tipo de origen (bases de datos, APIs, etc) y, además, mostrar datos al usuario de la forma más rápida posible, manteniendo al mínimo el consumo de recursos del servidor.

Y dado que esta nueva característica abre la puerta a funcionalidades muy interesantes de intercambio de datos en streaming, ya podemos verla reflejada en frameworks como ASP.NET Core o SignalR.

Publicado en Variable not found.

» Leer más, comentarios, etc...

Una sinfonía en C#

Métodos para trabajar con Arrays en Javascript

octubre 21, 2019 07:12

Esto viene de la curiosidad que me dio ver que varias personas utilizan el método map de Array para iterar aunque no deseen mapear los objetos, al preguntar el porqué de tal decisión me he dado cuenta que hay varios métodos del objeto Array poco conocidos que son muy útiles y, en algunas ocasiones, más adecuados según el caso de uso.

Los arrays en Javascript son cosa de todos los días, cuando manipulamos datos gran parte de las veces se trata de un array de elementos. Entonces conocer algunos métodos relacionados con ellos nos puede ser útil.
En este caso vamos a repasar algunos que me parece más útiles.

A los largo de algunos posts veremos:

  • Array.prototype.forEach
  • Array.prototype.map
  • Array.prototype.some
  • Array.prototype.filter
  • Array.prototype.find
  • Array.prototype.reduce
  • Array.prototype.findIndex

No todos separados, dependiendo un poco de lo largo que vayan quedando los posts.

Array.prototype.forEach

Empezamos con el que creo será el más común que utilizar al consultar un servicio.
forEach permite iterar todos los elementos de un array. Algo así:

var a = ['a', 'b', 'c'];
a.forEach(item => {
   console.log(item); });

Entonces en lugar de iterar con un for clásico (clásico para los que estudiamos programación estructurada) con forEach se recorre todo el array y nos da una referencia en el parámetro item.

Algunas características del forEach:

  • La cantidad de elementos a recorrer es establecida antes de iniciar el bucle, por lo tanto si agregamos un elemento dentro del forEach el mismo no será visitado.
  • Siempre retorna undefined, por lo tanto no es posible encadenarlo
  • No es posible interrumpir su ejecución (excepto con una excepción)
  • Si un elemento cambia y forEach no ha pasado aún por él se leerá el valor actualizado.
  • Si un elemento no visitado es borrado no será visitado.
  • Si un elemento ya visitado es borrado el resto de los elementos no será visitado.

El callback que recibe forEach como parámetro recibe 3 argumentos

  • El elemento actual que se está visitando.
  • El índice del elemento actual.
  • Otro array.

This dentro del forEach.


El valor de this dentro del forEach es el contexto actual (window en el navegador), es posible pasar un segundo parámetro a forEach a modo de contexto.

function Counter() {
   this.sum = 0;
}
Counter.prototype.add = function(array) {
   array.forEach((entry)=>{
     this.sum += entry;
   }, this);
};

Si hacemos:

var c = new Counter();
c.add({1,2,3});

el resultado es la suma, ya que el acumulador de this es el miembro sum del objeto Counter.

Y para qué es el tercer parámetro? un array?

El tercer parámetro que recibe el callback es el array original, ya que en Javascript los parámetros se pasan por valor (es decir, son copias) si hacemos esto:

var a = [1,2,3];
a.forEach(function(item, index, aa){
     item = 0;
});

Si comprobamos el valor del array a vemos que los valores no cambiaron, si quisiéramos cambiarlos deberíamos operar sobre el tercer parámetro que es el orginal.

a.forEach(function(item, index, aa){
     aa[index] = 0;
});

al comprobar el valor del array original vemos que todos sus valores fueron sobre-escritos, mágico.

Bueno, lo dejó acá. Espero les sea útil. Nos leemos.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 376

octubre 21, 2019 07:00

Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

» Leer más, comentarios, etc...

Picando Código

Nintendo inventa el género de Fantasía Fitness con Ring Fit Adventure

octubre 19, 2019 12:30

Prepárate para embarcarte en una aventura épica en la que, para defenderte de tus enemigos, tendrás que moverte tú mismo. Ring Fit Adventure te invita a hacer ejercicio mientras lo pasas en grande.

Nintendo se ha propuesto que todos juguemos. Es su obsesión desde sus inicios: generar experiencias únicas que involucren a toda la familia. Ring Fit Adventure es su última vuelta de tuerca, porque revoluciona una vez más nuestra manera de jugar y, de paso, nos invita a ponernos en forma sin casi darnos cuenta. Es un nuevo concepto, la Fantasía Fitness: una aventura épica llena de desafíos donde aguardan innumerables enemigos y un malvado (¡y musculoso!) villano, y los jugadores deben atacar y defenderse con ejercicios como sentadillas, ejercicios de presión y flexiones. Esta vez, el jugador es el mando, y los dos accesorios, el Ring-Con y la cinta de la pierna, convierten los movimientos y ejercicios que hace en el mundo real en acciones dentro del juego. Ring Fit Adventure ya llegó a Nintendo Switch.

YouTube Video

En el Modo Aventura, los jugadores viajarán a través de un mundo de colores vibrantes, con el objetivo final de derrotar a un malvado dragón culturista, Draco. A medida que avanzan los niveles, los jugadores pueden plantar cara a sus enemigos en combates de fitness, utilizando sus brazos, piernas y abdomen para ganar puntos de experiencia. El nivel de precisión de los accesorios permite medir la calidad del ejercicio por lo que una sentadilla bien hecha infringirá más daño al enemigo que una hecha a medias. Asimismo, también podrán recolectar ingredientes para elaborar batidos que restauren su salud. Pero no solo se hace ejercicio en los combates: entre batalla y batalla, los jugadores deben trotar para avanzar, y pueden encontrar algunos métodos de transporte inusuales como las plataformas de lanzamiento accionadas por sentadillas o tener que remar en una tabla de paddle surf gracias a la fuerza de tus abdominales.

Aparte de la aventura principal, el modo partida rápida es una buena manera de disfrutar de Ring Fit Adventure en pequeñas dosis, ya que permite a los jugadores echar una partida en cualquier momento. Así, pueden aprovechar para ejercitarse de distintas maneras, alternándose con familiares y amigos en minijuegos y compitiendo para obtener la puntuación más alta. Los minijuegos abarcan una amplia variedad de actividades, desde romper cajas con aire comprimido por medio del Ring-Con, hasta elaborar piezas de alfarería a base de sentadillas.

Otros modos, como los retos básicos y las series, ofrecen más maneras de hacer ejercicio. Los retos básicos permiten a los jugadores elegir los ejercicios en los que quieran centrarse y realizarlos de manera individual. Las puntuaciones más altas se guardan para que todo el mundo pueda probar a batirlas. Las series ofrecen secuencias enlazadas de distintos ejercicios diseñadas según un tema o una parte del cuerpo específica. Este modo es ideal para centrarse en un grupo de músculos concretos que el jugador quiera mejorar, como, por ejemplo, las piernas, los hombros, el tren inferior o el tronco.

¿Y cómo funciona todo esto? Antes de comenzar una sesión de Ring Fit Adventure, los jugadores simplemente deben insertar los Joy-Con en los accesorios. La cinta de la pierna se coloca en la parte superior de la pierna izquierda, mientras que el Ring-Con se sostiene con ambas manos. El Ring-Con es un dispositivo electrónico flexible que ofrece resistencia y, además, contiene un sensor que detecta cambios y el esfuerzo realizado por el jugador. Ring Fit Adventure se puede ajustar a la habilidad del usuario, por lo que incluso los jugadores que no tengan mucha experiencia de fitness pueden determinar la intensidad de los ejercicios para que se adapten a su nivel. Así podrán disfrutar diariamente de ejercicios con los que se sientan cómodos.

La naturaleza divertida de Ring Fit Adventure motiva a los jugadores a hacer ejercicio regularmente mientras continúan su viaje y suben de nivel a su personaje en el juego. Y, gracias a Nintendo Switch, el juego se puede llevar a cualquier parte, lo que permite a los jugadores divertirse y sudar estén donde estén.

Además, usando el exclusivo modo Multitarea, los jugadores también pueden utilizar el accesorio Ring-Con con un controlador Joy-Con, sin necesidad de llevar consigo la consola Nintendo Switch. Así, mientras están sentados en el trabajo o en un banco en un parque, pueden ejercitarse con el accesorio Ring-Con y hacer repeticiones que se pueden sincronizar más tarde en su consola, para convertirlas en bonificaciones dentro del juego.

Más información:
http://www.nintendo.es/ringfitadventure
http://www.nintendo.es
https://www.nintendo.es/nintendoswitch
https://twitter.com/nintendoes
https://www.facebook.com/NintendoES
https://www.facebook.com/NintendoSwitchES
http://www.youtube.com/NintendoES
http://www.twitch.tv/nintendoes
https://instagram.com/nintendoes/
https://www.instagram.com/NintendoSwitchES

Nintendo, give me free stuff!

» Leer más, comentarios, etc...

Picando Código

EmacsConf 2019 – La conferencia online sobre Emacs

octubre 18, 2019 05:40

El 2 de noviembre se va a celebrar EmacsConf, conferencia online sobre la alegría de Emacs, Emacs Lisp y memorizar secuencias de teclado.

EmacsConf

La conferencia va a ser de 9:00 a 17:00 EDT / 13:00 a 21:00 UTC / 14:00 a 22:00 CET. Ya está publicada la agenda: y hay charlas sumamente interesantes. ¡Espero que se graben y publiquen online!

Entre las charlas va a haber una actualización sobre la comunidad de Emacs por Sacha Chua, y actualización sobre su desarrollo por John Wiegley (mantenedor de Emacs).

Van a haber 3 temas principales:

Charlas orientadas al usuario

  • “Emacs para todos” por Sachin Patil
  • “Cómo un desarrollador/manager ciego usa Emacs a diario” por Parham Doustdar
  • “Gestionando tu vida con org-mode y otras herramientas” por Marcin Swieczkowski

Las tres suenan muy interesantes, particularmente la última, en lo personal para aprender más de cómo manejar mis notas y demás archivos org. Van a terminar con Lightning Talks entre las que descato “State of Retro Gaming in Emacs” 🤔, “Play and control your music with Emacs” y “Playing Emacs like an instrument”.

Desarrollo

  • “Zambullida en Magit” por Jonathan Chu
  • “Emacs como mi lenguaje de scripting” por Howard Abrams
  • “Revisión contínua de la calidad de tus paquetes” por Damien Cassou
  • “Desarrollo y Debugging Remoto Interactivo con TRAMP mode” por Matt Ray

Nuevamente termina con Lightning talks,incluyendo una charla sobre cóo usar Emacs para editar Java (intenté ésto más de una vez en otros tiempos y fracasé) y una charla titulada “VSCode es mejor que Emacs” 🙄

Futuro

  • “GNU Emacs como libertad del software en práctica” por Greg Farough
  • “Emacs: El editor para los próximos cuarenta años” por Perry E. Metzger

Pueden enterarse de más entrando al canal de IRC #emacsconf en irc.freenode.net, y la lista de correo emacsconf-discuss para ver discusión y anuncios sobre la conferencia y por supuesto el sitio web.

» Leer más, comentarios, etc...

Blog Bitix

Ventajas de usar un tipo específico para los identificadores de las entidades en vez de un tipo básico

octubre 18, 2019 02:30

Java
jOOQ

Al persistir una entidad de dominio en la base de datos su identificador se guarda como un tipo de datos soportado por la base de datos. Si es una base de datos relacional habitualmente es el equivalente a un bigint o en una base de datos de documentos quizá un UUID. En las entidades de dominio el tipo de datos usado para el identificador es el equivalente de la base de datos en el lenguaje de programación. Por ejemplo, si en una base de datos la clave primaria es un bigint el identificador en la entidad de dominio es un Long. Esto es lo mas simple pero tiene algún inconveniente.

El inconveniente es que al ser el identificador un tipo de datos básico cualquier Long es aceptado, con lo que se hacen posibles errores o malos comportamientos al usar un identificador de otra entidad de dominio si también es un Long donde no se debería. El compilador no captura este tipo de errores porque entiende como correcto cualquier Long independientemente de su significado desde el punto de vista de la aplicación.

También en cierta medida es un problema en la legibilidad del código ya que el tipo de dato de una variable no es significativo para saber si es un identificador. También es un problema al trabajar con colecciones, los siguientes ejemplos de código demuestran que los tipos no son todo lo semánticos o significativos que deberían.

1
2
Long id = ...;
List<Long> ids = ...;

La solución es crear un tipo para cada identificador de cada entidad y en vez de usar un Long pasar a usar un ProductoId, UsuarioId, CompraId o como en el ejemplo EventId. Estas serían unas posibles implementaciones.

1
2
3
4
package io.github.picodotdev.domain.misc;
public interface EntityId {
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package io.github.picodotdev.domain.misc;
public abstract class LongId implements EntityId {
private Long value;
public LongId(Long value) {
this.value = value;
}
public Long getValue() {
return value;
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package io.github.picodotdev.domain.event;
import io.github.picodotdev.domain.misc.LongId;
import java.util.Objects;
public class EventId extends LongId {
public EventId(Long id) {
super(id);
}
@Override
public int hashCode() {
return Objects.hashCode(getId());
}
@Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (!(o instanceof EventId)) { return false; }
return Objects.equals(getId(), ((EventId) o).getId());
}
}

El tipo de las colecciones ahora son más semánticas además de que el compilador realizará comprobaciones de tipos.

1
2
EventId id = ...;
List<EventId> ids = ...;

En la popular herramienta ORM de persistencia Hibernate o JPA se puede usar el tipo propio para el identificador usando la anotación @Converter y en otra alternativa de persistencia para Java como jOOQ especificando en el generador el tipo que se quiere usar para una columna. En ambos casos hay que proporcionar una implementación que convierta del tipo de la base de datos al del identificador en el dominio y viceversa. Son muy simples.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package io.github.picodotdev.infrastructure.datasource.hibernate.converter;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import io.github.picodotdev.domain.event.EventId;
@Converter
public class EventIdConverter implements AttributeConverter<EventId, Long> {
@Override
public Long convertToDatabaseColumn(EventId id) {
return id.getValue();
}
@Override
public EventId convertToEntityAttribute(Long value) {
return new EventId(value);
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package io.github.picodotdev.infrastructure.datasource.jooq.converter;
import io.github.picodotdev.domain.event.EventId;
public class EventIdConverter implements Converter<Long, EventId> {
@Override
public Class<Long> fromType() {
return Long.class;
}
@Override
public EventId from(Long value) {
return new EventId(value);
}
@Override
public Class<EventId> toType() {
return EventId.class;
}
@Override
public Long to(EventId id) {
return id.getValue());
}
}

En una entidad de Hibernate los identificadores se definen de la siguiente forma.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package io.github.picodotdev.domain.event;
...
@Entity
public class Event {
@Id
@GeneratedValue
@Convert(converter = EventIdConverter.class)
private EventId id;
...
}

En jOOQ en la configuración del generador hay que especificar que para un campo se use un converter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
plugins {
id 'java'
...
id 'nu.studer.jooq' version '3.0.3'
}
...
jooq {
version = versions.jooq
edition = 'OSS'
mysql(sourceSets.main) {
jdbc {
driver = 'com.mysql.cj.jdbc.Driver'
url = "jdbc:mysql://localhost:3306/${mysqlDdlJooqSchema}"
user = 'root'
password = ''
}
generator {
name = 'org.jooq.codegen.DefaultGenerator'
database {
name = 'org.jooq.meta.mysql.MySQLDatabase'
inputSchema = mysqlDdlJooqSchema
outputSchema = 'application'
includes = """
 event
 """
excludes = ''
...
forcedTypes {
...
// Ids
 forcedType {
types = 'BIGINT'
userType = 'io.github.picodotdev.domain.event.EventId'
converter = 'io.github.picodotdev.infrastructure.datasource.jooq.converter.EventIdConverter'
expression = '.*\\.event\\.id'
}
}
}
generate {
javaTimeTypes = true
interfaces = false
pojos = true
records = true
relations = true
}
target {
packageName = 'io.github.picodotdev.infrastructure.datasource.jooq.entities'
directory = 'src/main/java-generated'
}
}
}
}
...

Con un tipo de datos propio para los identificadores es muy importante implementar correctamente los métodos equals y hashCode tanto en clases de identificadores como en las entidades de dominio ya que las colecciones de Java se basan en estos métodos para determinar si una colección contiene un elemento.

» Leer más, comentarios, etc...

Picando Código

Ex-Zodiac – juego inspirado en StarFox desarrollado con Godot

octubre 16, 2019 11:30

Ex-Zodiac es un shooter 3D bajo en polígonos, inspirado en varios shooters 2D y 3D, particularmente Star Fox (Starwing) de Super Nintendo.

Únete a <personaje principal sin nombre> mientras se aventura por la galaxia en una aventura para detener el levantamiento de la fuerza malévola conocida como Zodiac.

Vi imágenes del juego en Twitter y me encantó. Jugué mucho Star Fox para Super Nintendo y creo que todavía es un buen juego a pesar de sus años. Hay que admitir que no tiene el mejor framerate del mundo… Recordemos que llevó al sistema al límite de su rendimiento y hacía uso del chip Super FX, un coprocesador que aumentaba su capacidad gráfica.

Para aquellos que todavía tenemos ganas de jugar un rail shooter moderno al estilo de Star Fox, hay esperanza con Ex-Zodiac. Lo que va del juego captura la esencia de lo que hizo bueno a Star Fox, pero con el toque personal del autor y el dinamismo de ejecutarlo en un hardware que no está siendo exigido al máximo para renderizar los polígonos en pantalla:

YouTube Video

Los detalles visuales, el control y la música, está todo muy bien hecho. El juego está siendo desarrollado por Ben Hickling con el motor de videojuegos software libre Godot. ¡Se espera una demo pública del juego pronto! El video es de una versión alfa, pero ya se puede apreciar una misión completa y un jefe al final, y todo se ve precioso. Seguiremos el proyecto con atención, esperando que se publique para GNU/Linux y si soñar es gratis, por qué no, en Nintendo Switch.

La música está compuesta por TEK, y podemos escuchar algunos adelantos en SoundCloud:

No sé si Nintendo volverá a Star Fox en el corto plazo. Hay que agradecer que Star Fox 2 finalmente vio la luz con el Super Nintendo Classic, pero es una saga con un gran potencial. Star Fox Zero para Wii U pudo haber sido genial, pero el hecho de que te forzara a usar el pad del Wii U con movimiento, no ayudó. Además los atrasos hicieron que saliera en un momento que el Wii U -que ya venía vendiendo poco-, ya no tenía mucho Ímpetu. Personalmente me gustó, probablemente más que nada por las ganas de jugar un Star Fox moderno. Pero al final del día no dejaba de ser un reversionado de Star Fox 64 (que de todas formas fue un juego excelente), y después de vencer al jefe final me frustré tanto con los controles que nunca volví a tocarlo.

Cada tanto sigo jugando Star Fox 64 en mi 3DS, y tengo pendiente Star Fox 2 en el SNES Classic. Starlink: Battle For Atlas para Nintendo Switch fue bueno mientras duró. La versión de Switch cuenta con los personajes de Star Fox y misiones relacionadas. Supono que será lo más cercano que vamos a tener en Nintendo Switch por ahora. Pero no tiene tanta rejugabilidad como los originales de Nintendo.

El tema es que creo que con un poco de imaginación, se pueden contar historias súper interesantes con un grupo de mercenarios antropomórficos que manejan naves espaciales. Y ni que hablar de las posibilidades que ofrece el hardware hoy en día para crear experiencias de juego divertidas. Pero donde Nintendo falla en darnos un Star Fox clásico con hardware moderno, Ben Hickling viene al rescate con Ex-Zodiac.

Le deseo mucho éxito al proyecto y estaré atento a novedades. Muy destacable el trabajo de Ben Hickling. Pueden seguir avances de Ex-Zodiac en su página de itch.io, o seguir a Ben Hickling en Twitter.

 

» Leer más, comentarios, etc...

Picando Código

Emacs y enlaces simbólicos

octubre 15, 2019 09:10

Cuando intentamos abrir un enlace simbólico en Emacs, nos pregunta:


Symbolic link to Git-controller source file; follow link? (y or n)

Tengo mis archivos de configuración, o dotfiles (.spacemacs, .bashrc, etc), como enlaces simbólicos a proyectos bajo control de versiones. Así puedo ir gestionándolos a medida que les hago mejoras o agrego cosas, y puedo compartir la misma configuración en distintas computadoras.

Spacemacs enlace simbólico

Esto se gestiona en el paquete de control de versiones vc, en la variable vc-follow-symlinks. Su valor por defecto es ask, por lo que el sistema nos va a preguntar qué hacer.

Si respondemos que no, editamos el archivo a través del enlace simbólico. Esto significa que vamos a trabajar en el directorio del enlace y no vamos a tener acceso al sistema de control de versiones lo cual puede resultar peligroso.

Si respondemos que sí, VC va a seguir el enlace y usar el archivo al que enlaza.

En mi caso generalmente quiero seguir el enlace simbólico, así que agregué la siguiente línea a mi archivo de configuración de Spacemacs:

(setq vc-follow-symlinks t)

Con esa única línea de elisp, nos ahorramos tener que responder ‘y’ cada vez que intentamos abrir un enlace simbólico.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 375

octubre 15, 2019 12:22

Enlaces interesantes

Por si te lo perdiste...

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en: www.variablenotfound.com.

» Leer más, comentarios, etc...

Variable not found

Switch expressions en C# 8

octubre 15, 2019 06:18

.NET Core Seguimos descubriendo perlas en C# 8 que nos harán la vida algo más sencilla a los desarrolladores. En este caso, se trata de una pequeña adición al lenguaje que nos permitirá hacer más claras y concisas determinadas expresiones condicionales.

Para ponernos en situación, imaginemos que tenemos una expresión como la siguiente, donde retornamos el texto "Rojo" cuando le suministramos el valor de enumeración Color.Red, y "Desconocido" en otros casos. Algo fácil de solucionar utilizando el operador condicional ?:
enum Color { Purple, Red, Blue, Orange, Black, Pink, Gray, Green, White };
string GetColorName(Color color)
{
var str = color == Color.Red ? "Rojo" : "Desconocido";
return str;
}
Imaginemos ahora que la aplicación evoluciona y debemos añadir otro caso a esta condición, como el soporte para el color azul. No pasa nada, podemos seguir el mismo patrón, aunque empezaremos a notar que esto no va a escalar demasiado porque la legibilidad empieza a resentirse:
var str = color == Color.Red ? "Rojo" : color == Color.Blue ? "Azul" : "Desconocido";

Podemos suponer cómo acabará esto cuando el número de casos a contemplar comiencen a dispararse. Seguro que todos tenemos código como el siguiente, donde ya cuesta trabajo ver qué casos han sido implementados y, si son correctos:
var str = color == Color.Red ? "Rojo" : color == Color.Blue ? "Azul" : 
color == Color.Orange? "Naranja": color == Color.Purple? "Púrpura":
color == Color.Black? "Negro": color == Color.Green? "Verde":
color == Color.Purple? "Violeta": color == Color.Gray? "Gris":
color == Color.Pink? "Rosa": color == Color.White? "Blanco": "Desconocido";
Es cierto que hasta el momento teníamos soluciones más o menos razonables al problema. Por ejemplo, podríamos formatear el código para que quede más legible poniendo cada condición en una línea. Con esto solucionaríamos el problema de la legibilidad, pero no podríamos verificar su corrección, algo difícil de hacer a ojo si se trata de un buen número de opciones.
Fijaos que en el código anterior hemos repetido deliberadamente el caso Color.Purple. Es fácil pasar por alto este error cuando el código es extenso.
Por supuesto, podríamos considerar el uso de opciones más artesanas, como la implementación mediante diccionarios o similares, pero resultarían algo verbosas y no impedirían la duplicación de valores:
var dic = new Dictionary<Color, string>()
{
[Color.Red] = "Rojo",
[Color.Blue] = "Azul",
[Color.Orange] = "Naranja",
[Color.Purple] = "Púrpura",
[Color.Black] = "Negro",
[Color.Green] = "Verde",
[Color.Gray] = "Gris",
[Color.Purple] = "Violeta",
...
};
if (!dic.TryGetValue(color, out string result))
result = "Desconocido";
Pero lo más razonable sería refactorizar a un bloque switch. En este caso podríamos asegurar que no cometemos los errores de antes, pero a cambio tendríamos que introducir bastante código, lo cual incidiría negativamente en la legibilidad:
string result;
switch(color)
{
case Color.Red:
result = "Rojo";
break;
case Color.Blue:
result = "Azul";
break;
case Color.Orange:
result = "Naranja";
break;
case Color.Purple:
result = "Púrpura";
break;
...
default:
result = "Desconocido";
break;
}
Pues bien, en este punto es donde entran las expresiones switch de C# 8, que nos permiten implementar una mezcla con lo mejor de las opciones anteriores: la inmediatez del operador condicional ? con la potencia del switch:
var str = color switch
{
Color.Red => "Rojo",
Color.Blue => "Azul",
Color.Orange => "Naranja",
Color.Purple => "Púrpura",
Color.Black => "Negro",
Color.Green => "Verde",
Color.Gray => "Gris",
Color.Pink=> "Rosa",
_ => "Desconocido"
};
Observad que sintácticamente recuerda algo a los bloques switch de toda la vida, pero tiene algunas diferencias importantes:
  • La variable objeto de la condición aparece antes de la palabra clave switch.
  • Se usa "=>" para determinar el retorno en cada caso.
  • Cada opción se resuelve en una expresión, no hay bloques de código ni break para distinguirlas.
  • El caso default se implementa también de forma más concisa, con el carácter de descarte "_".
Por último, es interesante indicar que, dado que internamente se comporta como un switch, es posible utilizar toda la potencia que últimamente se ha dado a este tipo de construcciones con pattern matching para implementar escenarios más complejos:
object obj = GetSomething();
Console.WriteLine(obj switch
{
Color color when color == Color.Red => "Rojo",
Color color => color.ToString(),
string str => str,
int i => i.ToString("#,##0")
});

Publicado en: www.variablenotfound.com.

» Leer más, comentarios, etc...

Blog Bitix

Microservicios con Spring Cloud, Consul, Nomad y Traefik

octubre 12, 2019 12:30

Sin entrar a si los microservicios son adecuados o no son adecuados en una aplicación, está claro que si se utilizan estos tienen varias necesidades. Un servicio de registro y descubrimiento, configuración centralizada, tolerancia a fallos, gateway/load balancer/reverse proxy, trazabilidad y métricas, autenticación, orquestación, … Los microservicios quiza no sean un gran monolito, quizá mas pequeños y con funcinalidad más acotada, pero el hecho de que se comuniquen a través de un medio más complejo y menos fiable como la red en vez de una llamada a un método y sean más numerosos hacen que la complejidad sea incluso mayor. Este artículo propone un ejemplo con Spring Cloud para los servicios, Consul para el registro y descubrimiento, Nomad para la orquestación y Traefik como gateway.

Java
Spring

En otro artículo mostraba un ejemplo de microservicios con Spring Cloud usando únicamente herramientas de Spring. Cada una de esas herramientas cubren una funcionalidad que necesitan los microservicios. Entre ellas:

  • Registro y descubrimiento, con Eureka. Los microservicios son numerosos, de vida efímera creándose y destruyéndose en diferentes ubicaciones por lo tanto necesitan una forma de localizarse unos a otros, la forma para encontrarse es acudiendo a un servicio donde se registran cuando se inician y se descubren cuando necesitan la ubicación de otro servicio.
  • Configuración centralizada, con Spring Cloud Config. Dado el número de microservicios actualizar la configuración de cada uno de ellos puede ser un problema, además dado que se pueden iniciar en diferentes ubicaciones aprovisionarles la configuración adecuada es un reto. En vez de aprovisionar la configuración otra técnica es hacer que cuando se inicien la obtengan de un servicio donde queda centralizada la configuración.
  • Tolerancia a fallos, con Hyxtrix y Resilience4j. El medio de comunicación de los microservicios es a través de la red un medio mucho menos confiable que una llamada a un método en un lenguaje de programación en una aplicación monolítica. De modo que los microservicios han de estar preparados para tolerar fallos en sus comunicaciones con otros servicios.
  • Gateway, load balancer y reverse proxy con tolerancia a fallos, con Zuul. Para aumentar la disponibilidad, escalabilidad y tolerar fallos en algunos servicios se suelen crear varias instancias de cada microservicio pero tener varias instancias hace que sea necesario balancear la carga entre cada una de las instancias. Para que los clientes sean agnósticos del número de instancias se emplea un gateway que proporciona balanceo de carga e implementa a su vez patrones de tolerancia a fallos.
  • Trazabilidad y correlación de trazas entre diferentes servicios, con Spring Cloud Sleuth. Una petición puede desencadenar una cadena de peticiones entre diferentes servicios ubicados en múltiples nodos, para tareas de diagnóstico en caso de querer investigar un bug o que ha ocurrido es necesario correlacionar todas las trazas que ha desencadenado una petición, se implementa asignado un identificativo global a la petición que es transmitido en las llamadas de microservicio a microservicio.

En otro ejemplo sobre OAuth con Spring mostraba otra funcionalidad:

Los microservicios también necesitan monitorización y métricas, en el ejemplo Monitorizar una aplicación Java de Spring Boot con Micrometer, Prometheus y Grafana:

  • Con Prometheus y Grafana. Nuevamente el número de instancias que requiere una arquitectura orientada a microservicios origina la necesidad en mayor medida de conocer el estado del sistema, ya sean métricas de los sistemas como uso de CPU, memoria o almacenamiento o de la aplicación como peticiones por segundo y porcentaje de correctas e incorrectas.

En esta lista falta un orquestador para el despliegue de los microservicios, que se encargue de su ciclo de vida, escalado de instancias y despliegue con estrategias rolling, blue/green y canary. Es una cosa que le faltaba al ejemplo de microservicios con Spring Cloud.

Además, en este ejemplo reemplazo varias de estas herramientas de Spring. Sustituyo el servicio de registro y descubrimiento proporcionado por Eureka por Consul, el gateway, load balancer y reverse proxy proporcionado por Zuul por Traefik y añado el orquestador de microservicios Nomad.

Consul Nomad Traefik

Traefik se configura con los servicios iniciados en los contenedores de Docker utilizando junto con los bloques o stanzas de config y labels en la definición de los servicios de Nomad. Según el criterio definido por el servicio Traefik es capaz de redirigir el tráfico que le llegue al servicio apropiado, entre las posibilidades que puede realizar Traefik es balanceo de carga entre las múltiples instancias que se hayan definido pero también implementa patrones de tolerancia a fallos con reintentos, el patrón circuit breaker o limitar el tráfico para evitar saturar a un servicio con demasiadas peticiones.

El esquema de servicios sería el siguiente. Los job son enviados a Nomad desde la linea de comandos que inicia los contenedores en Docker y registra los servicios en Consul, Traefik monitoriza los contenedores que se inician en Docker y se autoconfigura según las propiedades de los labels definidos para los contenedores. Una vez iniciados los servicios desde la terminal con un curl o desde la aplicación cliente que accede a Consul para conocer la ubicación del servicio de Traefik envían una petición a Traefik que haciendo balanceo de carga la reenvía a una de las instancias del servicio, el servicio responde y Traefik envía la respuesta al cliente. Para ser más funcional Traefik debería configurarse a partir de Consul en vez de Docker para posibilitar que los contenedores pudieran estar en varios nodos.

Esquema arquitectura

La ejecución del ejemplo requiere Docker ya que es en este caso el driver empleado en Nomad para ejecutar los servicios del servicio de configuración, el gateway, el servicio y el cliente del servicio. Nomad además se encarga de registrar los servicios en el servicio de registro y descubrimiento de Consul.

Los contenedores de Docker se añade a una misma red para que puedan comunicarse entre ellos, ha de ser así hasta que no se resuelva una petición de Docker para que los contenedores puedan comunicarse con la máquina host que los alberga.

1
$ docker network create --subnet 172.30.0.0/16 nomad

Poteriormente hay que ejecutar Consul y Nomad tras lo cual se puede acceder a sus consolas de estado.

1
2
$ consul agent -dev -ui -client=0.0.0.0
$ nomad agent -dev

Enviar a Nomad los job de Traefik tras lo cual se puede acceder a su consola de estado. El siguiente paso es enviar el job del servicio que proporciona la configuración a los microservicios. Lo anterior únicamente es infraestructura aún no hay ningún servicio que proporcione alguna funcionalidad, la funcionalidad que proporciona el servicio implementado con Spring es simplemente devolver un mensaje como respuesta a la petición que se le realice, se envía el job del servicio a Nomad. Finalmente, el servicio es consumido por un cliente que realiza una petición al servicio cada 1 segundo.

1
2
3
4
5
6
$ ./gradlew assemble
$ nomad job run nomad/traefik.nomad
$ nomad job run nomad/configserver.nomad
$ nomad job run nomad/service.nomad
$ nomad job run nomad/client.nomad

Definición de un servicio en un job para Nomad. count define cuantas instancias del servicio se inicia, la stanza update define como será la actualización cuando se actualice el servicio, la stanza labels contiene la configuración para Traefik, check define los parámetros para la monitorización.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
job "service" {
 datacenters = ["dc1"]
group "service" {
 count = 2
update {
 max_parallel = 1
 health_check = "checks"
 min_healthy_time = "20s"
 healthy_deadline = "10m"
 progress_deadline = "20m"
 canary = 1
 stagger = "15s"
}
task "service" {
 driver = "docker"
config {
 image = "openjdk:11-jdk"
 args = [
"bash",
"-c",
 "(cd /app && java -jar /app/service/build/libs/service-1.0.jar --port=8080)"
]
port_map {
 http = "8080"
}
 network_mode = "nomad"
 extra_hosts = [
"traefik:172.30.0.3"
]
 volumes = [
"/home/picodotdev/Software/personal/blog-ejemplos/SpringCloudConsulNomadTraefik/:/app"
]
labels {
 traefik.http.middlewares.service1-stripprefix.stripprefix.prefixes="/service",
 traefik.http.middlewares.service1-retry.retry.attempts="10",
 traefik.http.routers.service1.middlewares="service1-stripprefix,service1-retry",
 traefik.http.routers.service1.rule="PathPrefix(`/service`)",
 traefik.http.services.service1.loadbalancer.server.port="8080"
}
}
service {
 name = "service"
 port = "http"
check {
 type = "http"
 port = "http"
 path = "/actuator/health"
 interval = "5s"
 timeout = "2s"
}
}
resources {
 cpu = 200
 memory = 1024
network {
 mbits = 20
port "http" {}
}
}
}
}
}

Tanto Consul, Nomad como Traefik ofrecen una consola para ver su estado ubicadas en las siguientes direcciones respectivamente accesibles con el navegador http://127.0.0.1:8500, http://127.0.0.1:4646, http://127.0.0.1:8092.

Consolas de administración de Consul, Nomad y Traefik

El código del servicio, del cliente implementados con Spring y la salida del cliente son los siguientes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package io.github.picodotdev.blogbitix.springcloud.service;
...
@RestController
public class DefaultController {
@Autowired
private DefaultConfiguration configuration;
@Autowired
private Tracing tracing;
@Autowired
private Tracer tracer;
private Random random;
private Counter counter;
public DefaultController(MeterRegistry registry) {
this.random = new Random();
this.counter = Counter.builder("service.invocations").description("Total service invocations").register(registry);
}
@RequestMapping("/")
public String home(HttpServletRequest request) throws Exception {
counter.increment();
// Timeout simulation
 //Thread.sleep(random.nextInt(4000));

TraceContext.Extractor<HttpServletRequest> extractor = tracing.propagation().extractor((HttpServletRequest carrier, String key) -> { return carrier.getHeader(key); });
Span span = tracer.nextSpan(extractor.extract(request));
System.out.printf("Service Span (traceId: %s, spanId: %s)%n", span.context().traceIdString(), span.context().spanIdString());
return String.format("Hello world (url: %s, remoteAddress_%s, localAddress: %s, traceId: %s, spanId: %s, key: %s)", request.getRequestURL(),
request.getRemoteAddr(), request.getLocalAddr(), span.context().traceIdString(), span.context().spanIdString(), configuration.getKey());
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package io.github.picodotdev.blogbitix.springcloud.client;
...
@Component
public class ProxyService {
@Autowired
private LoadBalancerClient loadBalancer;
@Autowired
private Tracing tracing;
@Autowired
private Tracer tracer;
private CircuitBreakerConfig circuitBreakerConfiguration;
private TimeLimiterConfig timeLimiterConfiguration;
private HttpClient client;
public ProxyService() {
circuitBreakerConfiguration = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.recordExceptions(IOException.class, TimeoutException.class)
.build();
timeLimiterConfiguration = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofMillis(2500))
.cancelRunningFuture(true)
.build();
client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();
}
public String get() {
ServiceInstance instance = loadBalancer.choose("traefik");
URI uri = instance.getUri();
String resource = String.format("%s%s", uri.toString().replace("127.0.0.1", "traefik"), "/service");
HttpRequest.Builder r = null;
try {
r = HttpRequest.newBuilder(new URI(resource)).GET();
} catch (Exception e) {
return getFallback();
}
final HttpRequest.Builder request = r;
Span span = tracer.newTrace().start();
TraceContext.Injector<HttpRequest.Builder> injector = tracing.propagation().injector((HttpRequest.Builder carrier, String key, String value) -> { carrier.header(key, value); });
injector.inject(span.context(), request);
System.out.printf("Client Span (traceId: %s, spanId: %s)%n", span.context().traceIdString(), span.context().spanIdString());
CircuitBreaker circuitBreaker = CircuitBreaker.of("resilience4jCircuitBreakerProxyService", circuitBreakerConfiguration);
TimeLimiter timeLimiter = TimeLimiter.of(timeLimiterConfiguration);
Supplier<CompletableFuture<String>> get = () -> {
return CompletableFuture.supplyAsync(() -> {
try {
HttpResponse<String> response = client.send(request.build(), HttpResponse.BodyHandlers.ofString());
return response.body();
} catch (Exception e) {
return getFallback();
}
});
};
Callable<String> getLimiter = TimeLimiter.decorateFutureSupplier(timeLimiter, get);
Callable<String> getCircuitBreaker = CircuitBreaker.decorateCallable(circuitBreaker, getLimiter);
return Try.of(getCircuitBreaker::call).recover((throwable) -> getFallback()).get();
}
private String getFallback() {
return "Fallback";
}
}

Como hay 2 instancias del servicio y Traefik realiza balanceo de carga utilizando el algoritmo round robbin se observa en la salida con las respuestas que la dirección IP que ha atendido la petición es alternativamente una de las dos instancias del servicio.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
...
Service response: Hello world (url: http://172.30.0.3/, remoteAddress_172.30.0.3, localAddress: 172.30.0.4, traceId: 63afa4d0cd4f466c, spanId: 4719dfcc16b6104e, key: value)
Client Span (traceId: 57eeaa436aa09238, spanId: 57eeaa436aa09238)
Service response: Hello world (url: http://172.30.0.3/, remoteAddress_172.30.0.3, localAddress: 172.30.0.5, traceId: 57eeaa436aa09238, spanId: 26dc213be2d933ac, key: value)
Client Span (traceId: 23c748bf222052a6, spanId: 23c748bf222052a6)
Service response: Hello world (url: http://172.30.0.3/, remoteAddress_172.30.0.3, localAddress: 172.30.0.4, traceId: 23c748bf222052a6, spanId: 0404d949c6e04c18, key: value)
Client Span (traceId: c45d66a4ec9cf14c, spanId: c45d66a4ec9cf14c)
Service response: Hello world (url: http://172.30.0.3/, remoteAddress_172.30.0.3, localAddress: 172.30.0.5, traceId: c45d66a4ec9cf14c, spanId: e7f6ccf2efb8234b, key: value)
Client Span (traceId: 2fdb3b71a682d2e6, spanId: 2fdb3b71a682d2e6)
Service response: Hello world (url: http://172.30.0.3/, remoteAddress_172.30.0.3, localAddress: 172.30.0.4, traceId: 2fdb3b71a682d2e6, spanId: 24ac2a8d2bfb1e6e, key: value)
Client Span (traceId: a33b010e02709c6a, spanId: a33b010e02709c6a)
Service response: Hello world (url: http://172.30.0.3/, remoteAddress_172.30.0.3, localAddress: 172.30.0.5, traceId: a33b010e02709c6a, spanId: 0abe6074fc277af6, key: value)
...

En un momento posterior si surge la necesidad de querer desplegar una nueva versión del microservicio basta con generar de nuevo el artefacto del microservicio, cambiando la versión en el archivo build.gradle. El despliegue de la nueva versión se realizan mediante la estrategia canary, manteniendo las instancias con la versión anterior del servicio y añadiendo una nueva con la nueva versión. Si se descubre algún error en la instancia canary se puede revertir el estado a la versión anterior, que consiste en detener la instancia canary. Una vez se comprueba que la instancia con la nueva versión funciona correctamente analizando sus trazas y métricas se envía la order a Nomad de promocionar las instancias de forma progresiva con la versión antigua a la nueva versión.

1
2
3
$ nomad job run nomad/service.nomad
$ nomad job promote service
$ nomad job revert service 0

El servicio exporta métricas en formato para Prometheus que con Grafana. Según se realizan peticiones al servicio el valor de métrica de contador de llamadas al servicio aumenta de forma progresiva.

1
2
3
4
$ curl http://127.0.0.1:8093/service/actuator/prometheus | grep "service.invocations"
# HELP service_invocations_total Total service invocations
# TYPE service_invocations_total counter
service_invocations_total 20.0

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./run.sh.

» Leer más, comentarios, etc...

Coding Potions

Tutorial básico Vue ≫ Cómo crear componentes y estructura de carpetas

octubre 09, 2019 12:00

Introducción

En este artículo vamos a echar un ojo a los componentes web, una pieza fundamental de VueJS y del desarrollo frontend a día de hoy.

Bien, si recuerdas, hace tiempo vimos qué es VueJS y cómo instalarlo, pero no vimos cómo empezar a usarlo propiamente dicho. Hoy vamos a aprender cómo se organizan los archivos en Vue y cómo crear tu primer componente web.

Pero antes vamos a ver el concepto de los web components por si todavía no lo controlas.

Qué son los componentes web

Logo componentes web

Los componentes web son un concepto relativamente nuevo, aunque realmente llevas utilizándolos mucho tiempo. Un componente web se trata de un elemento de la página web, con vista, estilos y lógica, que puedes reutilizar a lo largo de tu página web.

Realmente todas las etiquetas html son una especie de componentes web porque se componen también de esas partes.

Por ejemplo al crear un elemento html <input>, realmente estás creando una especie de componente web porque se compone del html que se pinta, los estilos que se pintan por defecto y a lógica de poder escribir.

Pues ahora imagínate que puedes crear tu propio componente con un html mucho más complejo, con más estilos CSS que los de por defecto y con una lógica mucho más compleja. Imagina poder crear un componente web llamado calendario. Simplemente poniendo en la página que lo necesites su etiqueta html, por ejemplo <calendar/> podrías crear un calendario totalmente funcional incluso con la lógica de pasar los meses y los años.

Los componentes no son únicos de Vue, es más, desde hace poco los puedes crear de forma nativa en javascript, pero Vue lo que hace es facilitarnos la tarea de crear los componentes web escribiendo menos código y pudiendo hacer cosas mucho más complejas.

Estructura básica de un proyecto Vue

Antes de empezar a crear componentes web es esencial que sepas la estructura que tiene un proyecto de VueJS para que sepas dónde va cada cosa. Los archivos que muestro a continuación son los que hay nada más crear el proyecto con el comando de Vue create:

Estructura de carpetas de Vue

📁 Carpeta node_modules

Como en todo proyecto javascript que utilice los paquetes NPM, aquí también existe esta carpeta en la que se encuentran todas las dependencias ya instaladas del proyecto. Si no sabes cómo utilizar NPM te recomiendo mi tutorial completo de NPM

📁 Carpeta public

En esta carpeta hay dos archivos:

  • favicon.ico: Es el icono que aparece al lado del nombre de la pestaña en el navegador, por defecto es el logo de Vue pero lo puedes cambiar por tu icono en formato .ico
  • public.html: Es el archivo html sobre el que se montará toda la página. Como hemos dicho en capítulos anteriores, al ser una aplicación SPA, todas las vistas se cargan dinámicamente sin tener que recargar la paǵina. Esto significa que toda la página se incrustará dentro de la etiqueta:

    <div id="app"></div>
    

    Por lo que toda la página compartirá este html. Por cierto, si quieres insertar nuevos archivos de estilos o archivos javascript en el head de esta página NO tienes que llamar a tus archivos aquí, esto lo haremos con webpack.

📁 Carpeta src

En la carpeta src se sitúan los archivos fuentes de nuestra página web. En esta carpeta es dónde se crea todo, es decir, aquí van los componentes y las vistas, así como todo el resto de archivos necesarios para hacerlos funcionar.

  • assets: En esta carpeta se encuentran todos los archivos estáticos de tu aplicación. Cuando creas la estructura se añade el archivo logo.png de ejemplo. Cuando quieras meter una imagen, fuentes, o cosas así lo puedes hacer en esta carpeta. Vue y webpack se encargarán de servir los archivos de esta carpeta para que los puedas llamar desde las vistas.
  • components: Aquí se crearan todos los componentes web. Al crear el proyecto te viene el componente HelloWorld.vue de ejemplo. Lo más recomendable es que dentro de esta carpeta crees carpetas para separar los componentes entre sí. Lo que se suele hacer es separar los componentes por páginas o por área a la que pertenece.
  • views: Si al crear el proyecto has seleccionado manualmente que instale vue router para crear las vistas, aparecerá esta carpeta (si no lo has hecho cuando veamos las vistas te enseñaré como instalarlo en un proyecto ya creado). En esta carpeta se sitúan los componentes encargados de cada una de las vistas y rutas de la página. Lo normal es que haya un componente por cada ruta de la página.

📄 Otros archivos

Aparte de las carpetas que acabamos de ver, Vue crea estos archivos. En mi caso al crear el proyecto de Vue seleccioné que las configuraciones vayan en archivos separados para una mejor gestión.

  • .browserslistrc: En este archivo se especifican cuántas versiones hacia atrás se quiere tener compatibilidad con los nevegadores.
  • .eslintrc.js: Aquí se establecen las normas y las configuraciones del eslint, es decir, de la herramienta que te dice los errores y los warnings cuando guardas los archivos. Si hay una regla que no la quieres, aquí la puedes personalizar o quitar directamente.
  • .gitignore: Aquí le dices al git qué ficheros quiere que ignore. Por defecto Vue te habrá colocado los recomendados.
  • babel.config.js: Configuraciones de babel, la herramienta que transpila el javascript generado a código entendible por navegadores antiguos.
  • package.json y package-lock.json: Donde se establecen las versiones de la librerías requeridas. Además se pueden establecer otros parámetros como el nombre de la aplicación, versión, autores, etc.
  • postcss.config.js: Aquí van las configuraciones del transpilador de CSS, en mi caso uso sass.
  • README.md: Archivo que se muestra al entrar en un proyecto en el github o gitlab. Aquí puedes escribir información sobre el proyecto que creas conveniente.

Hello world. Cómo se crea un componente

Bien, pues ahora que hemos visto todo lo básico para empezar, vamos a ver por fin algo de código. Lo primero que tienes que hacer tras crear un proyecto es ejecutar npm run serve o vue serve para ejecutar vue en modo desarrollo y poder abrir la página que estamos desarrollando.

Si ahora abres localhost:8080en tu navegador verás la página de prueba de Vue con lo que has instalado. Hora de abrir el proyecto en tu editor de texto favorito, en mi caso el vscode.

Como hemos visto, los componentes se crean dentro de src/components, si abres esa carpeta te encontrarás con un archivo llamado HelloWorld.vue, ábrelo. Verás algo como esto:

<template>
<div class="hello">
    <h1></h1>
    <p>
      For a guide and recipes on how to configure / customize this project,<br />
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>
    <h3>Installed CLI Plugins</h3>
    <ul>
    <li>
        <a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a>
    </li>
    <li>
        <a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a>
    </li>
    </ul>
    <h3>Essential Links</h3>
    <ul>
    <li>
        <a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
    </li>
    <li>
        <a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a>
    </li>
    <li>
        <a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a>
    </li>
    <li>
        <a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a>
    </li>
    <li>
        <a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
    </li>
    </ul>
    <h3>Ecosystem</h3>
    <ul>
    <li>
        <a href="https://router.vuejs.org" target="_blank" rel="noopener" >vue-router</a>
    </li>
    <li>
        <a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
    </li>
    <li>
        <a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener" >vue-devtools</a>
    </li>
    <li>
        <a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a>
    </li>
    <li>
        <a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener" >awesome-vue</a>
    </li>
    </ul>
</div>
</template>

<script>
  export default {
    name: "HelloWorld",
    props: {
      msg: String
    }
  };
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
  h3 {
    margin: 40px 0 0;
  }
  ul {
    list-style-type: none;
    padding: 0;
  }
  li {
    display: inline-block;
    margin: 0 10px;
  }
  a {
    color: #42b983;
  }
</style>

Lo primero, no te asustes. Lo segundo, borra todo el contenido dentro de las etiquetas <template>y déjalo así:

<template>
    <div class="hello">
    Hello world
    </div>
</template>

<script>
  export default {
    name: "HelloWorld",
    props: {
      msg: String
    }
  };
</script>

<style scoped lang="scss">
  h3 {
    margin: 40px 0 0;
  }
  ul {
    list-style-type: none;
    padding: 0;
  }
  li {
    display: inline-block;
    margin: 0 10px;
  }
  a {
    color: #42b983;
  }
</style>

Si ahora abres [localhost:8080](http://localhost:8080) verás que la página ha cambiado y que ahora pone Hello world

Partes que componen un componente en VueJS

Si recuerdas lo que vimos anteriormente, los componentes se componen de 3 partes: la vista, los estilos y la lógica. Vue para diferencias estas 3 partes usa las etiquetas html:

  • Dentro de la etiqueta <template> está el código html del componente. Cada vez que llames al componente, Vue insertará el contenido de esta etiqyeta dentro del DOM de la página web.
  • Dentro de la etiqueta <script> está la lógica del componente. Aquí puedes crear métodos, variables, llamadas al back, etc, es decir, la funcionalidad y el código javascript que está relacionado con el template.
  • Dentro de la etiqueta <style>se encuentran los estilos del componente. Aquí es donde puedes crear estilos css o scss para los elementos que has creado en la etiqueta template.

Los archivos Vue se componen de estas partes en el mismo archivo (Single File Component), a diferencia de Angular que tiene la vista, estilos y lógica de cada componente en archivos separados. Hablemos un poco de cada una de las partes:

La vista

Como hemos dicho aquí puedes escribir los elementos HTML que quieres que tenga el componente cuando lo utilices. Vue cuando renderice el componente y su vista eliminará las etiquetas template y dejará solo su contenido.

Es importante saber que Vue tiene una limitación, no se pueden crear más de un elemento raíz, es decir, este componente no es válido y por tanto salta error:

<template>
  <div class="one"></div>
  <div class="tow"></div>
</template>

Como ves hay dos elementos raíz, los dos div. En cambio este componente si que sería válido:

<template>
  <div class="content">
    <div class="one"></div>
    <div class="tow"></div>
  </div>
</template>

La lógica

Aquí es el lugar en el que escribes la funcionalidad, es decir, el comportamiento del componente. Como veremos más adelante, aquí vas a poder controlar qué ocurre cuando se crea el componente, cuando se destruye, cuando cambia una variable, etc.

Por el momento lo que tienes que saber es que siempre que crees un componente tienes que escribir:

<script>
export default {
  name: "HelloWorld"
};
</script>

Esta es la parte mínima de un componente. En la etiqueta name puedes escribir el nombre del componente, pero siempre en PascalCase (la primera letra en mayúsculas, las palabras juntas y cada una con la primera letra en mayúscula). El campo name no es obligatorio pero viene bien para identificar el componente.

A diferencia de Angular, aquí no tienes que indicar explícitamente que coja la vista de otro archivo.

Creando el componente

Para crear los componentes, lo que yo hago es simplemente crear el fichero con el nombre del componente en PascalCase también (la primera letra en mayúsculas, las palabras juntas y cada una con la primera letra en mayúscula) y creo la estructura básica con todas las partes. Por ejemplo este componente lo crearía dentro de src/components/ con el nombre MiComponente.vue:

<template>
  <p>Mi primer componente en Vue</p>
</template>

<script>
  export default {
    name: "MiComponente"
  }
</script>

<style lang="scss" scoped>
</style>

En la etiqueta style he creado el parámetro lang para poder usar scss pero si quieres usar css básico no hace falta que la pongas (Si creaste el proyecto de Vue de manera manual te habrá preguntado si quieres preprocesadores CSS). También le meto el atributo scoped que sirve para encapsular los estilos.

Al poner scoped, lo que hace Vue es aislar esos estilos para que no afecten a otros componentes de otros archivos, lo que es muy recomendable.

Si dentro de un componente creo un elemento con una clase unos estilos y en otro componente de otro fichero creo la misma clase y le meto otros estilos, los estilos se van a pegar entre sí. Usando scoped tienes la ventaja de poder usar las clases que quieras dentro del componente asegurando que no van a haber conflicto con otros componentes.

Para usar este componente que acabas de crear tienes que hacer lo siguiente. Pongamos que lo quieres insertar en el componente Home de la carpeta /src/views (Si instalaste Vue con el create pero no de la forma manual, o no indicaste que instalara Vue Router puedes importar el componente dentro de App.vue para que veas el ejemplo).

Si abres este componente verás lo siguiente:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
      <HelloWorld msg="Welcome to Your Vue.js App" />
    </div>
</template>

<script>
  // @ es un alias a /src
  import HelloWorld from "@/components/HelloWorld.vue";

  export default {
    name: "home",
      components: {
        HelloWorld
    }
  };
</script>

Si te das cuenta ya se está usando el componente HelloWorld. Los componentes siempre se importan encima del export dentro de la etiqueta script.

<script>
  // @ is an alias to /src
  import HelloWorld from "@/components/HelloWorld.vue";
  import MiComponente from "@/components/MiComponente.vue";

  export default {
  ...
  }

Como dice el comentario, al importar, dentro de la ruta se coloca @ como atajo a la carpeta src. Esto es muy recomedable ponerlo.

Ahora toca añadirlo al objeto components de más abajo. Siempre que quieras usar un componente tienes que importarlo y añadirlo aquí, de lo contrario no funcionará.

components: {
  HelloWorld, 
  MiComponente;
}

Por último lo puedes colocar arriba en la vista. Vue por debajo lo que va a hacer es mirar el objeto components que hemos visto antes, y va a sustituir el nombre del componente en PascalCase por el mismo nombre pero en kebab-case. Esto se hace para que cuadren mejor con los elementos HTML. Por lo que solo tenemos que:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js App" />
    <mi-componente></mi-componente>
  </div>
</template>

Como ves también se pueden usar como PascalCase como el componente de HelloWorld pero es más recomendable en kebab-kase: hello-world

Otro detalle a tener en cuenta es que los componentes los puedes cerrar en la misma etiqueta de apertura:

<mi-componente />

Y listo, ya deberías ver el nuevo componente dentro de la página web. Cada vez que cambies algo de unos de los componentes vas a ver el cambio instantáneamente sin tener que recargar la web.

En conjunto quedaría así:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js App" />
    <mi-componente />
  </div>
</template>

<script>
  // @ is an alias to /src
  import HelloWorld from "@/components/HelloWorld.vue";
  import MiComponente from "@/components/MiComponente.vue";

  export default {
    name: "home",
    components: {
      HelloWorld,
      MiComponente
    }
  };
</script>

Conclusiones

Pues ya has visto cómo se crean los componentes y cómo se pueden usar. Lógicamente puedes meter componentes dentro de componentes que a su vez tienen más componentes. Cuanto más reutilices los componentes mejor. Si por ejemplo te creas un componente para crear botones, si los usas en toda la web, el día que tengas que cambiarlos solo lo tienes que hacer en un sitio.

En próximos capítulos veremos cómo se pueden personalizar los componentes para que sean flexibles y adaptables a cualquier situación.

Como último consejo para desarrollar con Vue te digo que siempre tengas la consola del navegador abierta. Muchas veces los fallos los detectas porque ha habido un error que se muestra ahí, aunque normalmente los errores te los dice Vue en la propia página.

» Leer más, comentarios, etc...

Picando Código

Thunderbird 78 tendrá soporte nativo para OpenPGP

octubre 08, 2019 08:35

A partir de la próxima versión del cliente de correo, Thunderbird tendrá soporte nativo para el cifrado de correos y firmas digitales usando el estándar OpenPGP.

Thunderbird OpenPGP

OpenPGP es un protocolo para el cifrado de comunicación por correo electrónico usando criptografía de llave pública. Está basada en el software PGP (Pretty Good Privacy) original. El protocolo define formatos estándar para mensajes cifrados, firmas y certificados para intercambiar claves públicas.

La nueva funcionalidad reemplazará a Enigmal -la extensión de Thunderbird- que continuará siendo soportada hasta el fin de soporte de Thunderbird 68, en el último cuarto de 2020. Thunderbird 70 estará disponible a principios de 2020.

Existen dos tecnologías que agregan soporte para cifrado punta-a-punta y firmas digitales en los correos electrónicos. Thunderbird ha ofrecido soporte nativo para S/MIME por muchos años y lo continúa haciendo. La extensión Enigmail ha permitido el uso de Thunderbird con software GnuGP externo para mensajes OpenPGP. Dado que los tipos de extensiones van a cambiar en la versión 78, la rama actual de Thunderbird 68.x va a ser la última que podrá ser usada con Enigmal.

Thunderbird 78 proveerá asistencia para migrar configuraciones actuales de Enigmal. El desarrollador de Enigmal, Patrick Brunschwig, trabajará con el equipo de Thunderbird en OpenPGP a partir de ahora. Comentó:

Siempre ha sido mi meta que el soporte para OpenPGP esté incluido en el núcleo del producto Thunderbird. Aunque marcará un final a una larga historia, después de trabajar en Enigmal por 17 años, estoy muy feliz con este resultado.

Los usuarios que no hayan usado Enigmal anteriormente necesitarán optar usar mensajería con OpenPGP, el cifrado no estará habilitado automáticamente. Sin embargo, Thunderbird 78 ayudará a los usuarios a descubrir la nueva funcionalidad.

Para promover la comunicación segura, Thunderbird 78 animará al usuario a realizar confirmación de la pertenencia de claves usadas por los emisores, notificará al usuario si las llaves de los emisores cambian inesperadamente, y si hay un problema, ofrecerá asistencia para resolver la situación.

Todavía no está decidido si Thunderbird 78 soportará las confirmaciones indirectas de pertenencia de claves usadas en el modelo Web Of Trust (WoT), o hasta qué punto. Sin embargo, compartir confirmaciones de pertenencias de claves hechas por el usuario e interacción con servidores de claves OpenPGP será posible.

Pueden leer más información y planes más detallados sobre OpenPGP en Thunderbird en la wiki de Mozilla.

» Leer más, comentarios, etc...

Variable not found

Error en proyectos gRPC al usar un nombre de usuario de Windows con espacios o caracteres especiales

octubre 08, 2019 02:07

gRPCComo un servidor, todos los que tengáis la inmensa fortuna de utilizar en Windows un nombre de usuario con espacios o caracteres especiales como "José María Aguilar", seguro que habéis encontrado alguna vez problemas con aplicaciones o herramientas que fallan cuando intentan acceder a contenidos de la carpeta C:\Users\<Tu nombre>:

Username chungo en Windows

De hecho, llevo ya varios encontronazos de este tipo en los últimos meses (por ejemplo, con Anaconda o con el SDK de Android para Windows), y el último lo he tenido al intentar utilizar las herramientas de Protobuf para la creación de servicios gRPC que, como sabéis, es una de las novedades incluidas en .NET Core 3.

Aunque el problema lo he encontrado trabajando con Visual Studio, ciertamente este IDE tiene poco que decir al respecto; ocurre lo mismo usando línea de comandos o cualquier otro entorno que se base en el tooling oficial de gRPC para .NET.

El problema

El problema es bastante sencillo de reproducir si usáis nombres de usuario de ese tipo. Basta con crear un proyecto de tipo "Servicio gRPC" e intentar compilarlo. Si lo hacemos desde Visual Studio, veremos el siguiente error:

Error 'protoc-gen-grpc: el sistema no puede encontrar la ruta especificada

Y si lo hacemos desde línea de comandos, no mejora mucho la cosa:
C:\test>dotnet new grpc
The template "ASP.NET Core gRPC Service" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on C:\test\test.csproj...
Restauración realizada en 96,36 ms para C:\test\test.csproj.

Restore succeeded.


C:\test>dotnet build
Microsoft (R) Build Engine versión 16.3.0+0f4c62fea para .NET Core
Copyright (C) Microsoft Corporation. Todos los derechos reservados.

Restauración realizada en 19,26 ms para C:\test\test.csproj.
--grpc_out : error : protoc-gen-grpc: El sistema no puede encontrar
la ruta especificada. [C:\test\test.csproj]

ERROR al compilar.

--grpc_out : error : protoc-gen-grpc: El sistema no puede encontrar
la ruta especificada. [C:\test\test.csproj]
0 Advertencia(s)
1 Errores

Tiempo transcurrido 00:00:00.68

C:\test>_
Me encantan estos errores que no dan pistas sobre el origen del problema ;)

La solución

Desde luego, y me lo apunto para mi próxima instalación de Windows, el mejor remedio sería no utilizar un nombre de usuario con espacios ni caracteres extraños. Un "jmaguilar" habría sido perfecto, ho hay necesidad de utilizar el nombre completo ;)
C:\Users\José María Aguilar> _
Pero si ya estamos en un momento en que esto no tiene solución sencilla, podéis seguir los pasos descritos a continuación:

1. Crear un enlace simbólico, o un junction link, por ejemplo en la raíz del disco duro, apuntando hacia el directorio donde se encuentra la carpeta packages de NuGet:
C:\> mklink /j "C:\.nuget" "C:\Users\José María Aguilar\.nuget"
Una vez ejecutado este comando, la carpeta se verá en el explorador de archivos como se muestra en la siguiente captura de pantalla:

  Junction link creado en la carpeta raíz

2. Establecer la variable de entorno NUGET_PACKAGES, que indica la ubicación de la carpeta Packages de NuGet, utilizando el enlace simbólico. En mi caso, es algo como:
NUGET_PACKAGES=C:\.nuget\packages
¡Y esto es todo! Espero que os resulte útil, y recordad que este mismo truco podéis usarlo para otros escenarios en los que ocurra lo mismo :)

Publicado en: Variable not found.

» Leer más, comentarios, etc...

Fixed Buffer

Worker Service: Cómo crear un servicio .Net Core 3 multiplataforma

octubre 08, 2019 08:00

La imagen muestra el logo de .Net Core 3.0

Hace unos meses, hablamos sobre como crear servicios multiplataforma con .Net Core 2, donde veíamos que había que hacer algunas «perrerías» para poder conseguirlo… Ha llegado .Net Core 3, y me ha parecido interesante hablar sobre la nueva manera que nos trae de conseguir esto.

En primer lugar, tenemos una nueva plantilla disponible para esto: Worker Service. Usando esta plantilla, vamos a poder tener un ejemplo para construir nuestro servicio. Aunque perfectamente podemos hacerlo desde una aplicación de consola añadiendo nosotros el código, vamos a «estrenar» la plantilla (si nos dan trabajo hecho, tampoco vamos a decir que no… xD )

Creando la solución

Lo primero por supuesto, es crear nuestra solución, y en ella, vamos a elegir la plantilla «Servicio de trabajo» (Worker Service en inglés):

La imagen muestra la plantilla seleccionada

Esto nos va a crear una solución con dos archivos, Program.cs y Worker.cs. Si abrimos Program.cs, vamos a poder comprobar que nuestro proyecto no es más que una aplicación de consola que crea un «Host» (al igual que hacíamos en .Net Core 2.X).

namespace PostWorker
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
    }
}

El segundo fichero que tenemos, Worker.cs, tiene una pinta parecida a esta:

namespace PostWorker
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

La principal novedad al crear nuestras tareas dentro del servicio, es que ahora heredamos de la clase abstracta «BackgroundService» (y no de IHostedService como hacíamos en .Net Core 2.X). Esto simplemente es para aportarnos una capa de abstracción sobre su funcionamiento, y realmente es esta clase la que implementa IHostedService y nos ofrece 3 métodos para trabajar con ella:

protected abstract Task ExecuteAsync(CancellationToken stoppingToken)
public virtual Task StartAsync(CancellationToken cancellationToken)
public virtual Task StopAsync(CancellationToken cancellationToken)        

Para crear nuestro servicio básico, tal como lo hace el ejemplo, basta con implementar el primero de ellos (que además al ser abstracto estamos obligados a implementar). Pero vamos a profundizar un poco más…

El primero de ellos, va a ser lo que queremos que se ejecute dentro de nuestro servicio, con la implementación por defecto, cuando arranque el servicio, se va a llamar directamente a ese método en una tarea. De igual manera, cuando el servicio se pare, se cancelará el token. Es importante tener en cuenta el CancellationToken como sistema de control del ciclo de vida, para evitar tener tareas bloqueadas al parar nuestro servicio.

Si necesitamos una funcionalidad un poco más avanzada, como ejecutar algo de código previo al arranque o en la parada, lo que vamos a tener que hacer es sobrescribir los métodos StartAsync y StopAsync según necesitemos, ya que no es obligatorio hacerlo con los dos. Un caso en el que nos podría hacer falta, es cuando necesitamos diferenciar las labores de arranque del servicio con las propias de ejecución. Por ejemplo, si quieres loguear cuando arranca o para tu servicio .Net Core 3:

namespace PostWorker
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        public override async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Worker starts");
            await base.StartAsync(cancellationToken);
        }

        public override async Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Worker stops");
            await base.StopAsync(cancellationToken);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

Es importante señalar, que podemos registrar tantos «Workers» como necesitemos, basta con que lo añadamos en el inyector de dependencias. Por ejemplo, si tuviésemos una clase Worker1 y otra Worker2, nuestro Program.cs se vería algo así:

namespace PostWorker
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker1>();
                    services.AddHostedService<Worker2>();                    
                });
    }
}

Con esto, ya tenemos un código perfectamente funcional como servicio, de hecho, si lo instalamos en Linux como servicio (daemon), podremos comprobar que funciona perfectamente. En cambio, si lo instalamos en Windows, para nuestra sorpresa (o no), simplemente esto no va a funcionar.

Instalando nuestro servicio .Net Core 3 en Windows

Si alguna vez has creado un servicio en Windows, sabes que tiene sus cositas… En .Net Core 2.X, teníamos que hacer ciertas perrerías para conseguirlo, pero por suerte, ahora tenemos un paquete NuGet que nos permite hacerlo sin dificultades (básicamente, hace las perrerías por nosotros). Este paquete es «Microsoft.Extensions.Hosting.WindowsServices«, basta con que lo añadamos a nuestro proyecto y que añadamos su uso en Program.cs con «UseWindowsService» sobre el HostBuilder:

namespace PostWorker
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseWindowsService() //Registramos el paquete
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();                  
                });
    }
}

Este paquete lo que va a hacer, es registrar los servicios necesarios en el inyector de dependencias si corremos sobre Windows, y no hacer nada en el resto de los casos.

Con esto, ya tenemos nuestro servicio en .Net Core 3 listo para instalarlo en cualquier máquina, independientemente del sistema operativo que utilicemos. Si quieres probarlo tú mismo, he dejado el código en GitHub para que puedas salsearlo sin problemas.

**La entrada Worker Service: Cómo crear un servicio .Net Core 3 multiplataforma se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 374

octubre 07, 2019 06:15

Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros


Publicado en: www.variablenotfound.com.

» Leer más, comentarios, etc...

Blog Bitix

Guía de inicio del gestor de terminales y sesiones tmux

octubre 04, 2019 04:00

Las personas que usan de forma intensiva la terminal seguramente usando un mutiplexador de terminales como tmux su trabajo es facilitado. Tmux permite dividir una terminal en paneles, ventanas independiente y sesiones. Usando sus múltiples combinaciones de teclas se divide una terminal o una ventana de forma horizontal y vertical en paneles del tamaño que se desee pudiendo de esta forma visualizar al mismo tiempo varias terminales ubicadas en cada panel. También se puede crear una configuración para iniciar tmux con la misma disposición de paneles, ventanas y sesiones.

GNU
Linux

Las terminales gráficas como GNOME Terminal y KDE Konsole soportan pestañas e incluso desde un entorno gráfico en GNU/Linux están disponibles según la distribución varias terminales de texto accesibles con la combinación de teclas Ctrl+Alt+F3 y Ctrl+Alt+F4, con Ctrl+Alt+F2 se puede retornar a la interfaz gráfica. Sin embargo, ninguna de estas opciones permite dividir la misma terminal en varias ventanas o paneles para realizar operaciones y ver los resultados al mismo tiempo. Por otro lado cuando realizamos una sesión SSH y esta finaliza o termina abruptamente por un fallo en la conexión los procesos que se hayan iniciado desde ella son terminados lo que es especialmente grave si se está realizando una operación importante que puede ocasionar problemas.

Tmux es un multiplexador de terminales con soporte para iniciar sesiones. Con tmux en una misma terminal o sesión SSH es posible dividirla en varios paneles y ventanas. También permite iniciar sesiones y salir de ellas sin que los procesos que están corriendo sean terminados lo que permite iniciar una sesión por ejemplo en el trabajo, dejarla suspendida y luego continuarla desde otro equipo, ubicación o ser iniciada por una persona y continuada por otra.

Sesión de tmux en la terminal de GNOME

Tmux al ser un programa de la terminal todas sus opciones se realizan con el teclado, y no son pocas las combinaciones de teclas de su cheatsheet o chuleta. Algunas opciones básicas necesario conocer con son:

  • Dividir una terminal en paneles verticales y horizontales, Ctrl-b “, Ctrl-b %.
  • Cambiar entre paneles, Ctrl-b q 0..9.
  • Cambiar tamaño de un panel, Ctrl-b Up, Ctrl-b Down, Ctrl-b Left, Ctrl-b Right. Una panel se maximiza y minimiza con Ctrl-b z.
  • Cerrar un panel, Ctrl-b x.
  • Cerrar una sesión Ctrl-b :, kill-session.
  • Crear, moverse a otra ventana y cerrar una ventana, Ctrl-b c, Ctrl-b 0..9, Ctrl-b ,.
  • Hacer scroll en las ventanas, Ctrl-b [.

Para facilitar un poco su uso y poder cambiar entre paneles y hacer scroll si se usa en un entorno gráfico se pueden habilitar las funciones del ratón. Basta editar el archivo de configuración ~/.tmux.conf o introducir la opción con Ctrl-b :. En un entorno gráfico habilitar el soporte para el ratón cambia el comportamiento de copiar y pegar, para seleccionar texto hay que hacer uso de la tecla Shift a la vez que se selecciona el texto con el botón izquierdo del ratón.

1
set-option -g mouse on

Para automatizar la configuración inicial de tmux soporta un archivo para personalizarlo a través de un script con comandos. Así por ejemplo si siempre se desea una misma configuración de paneles y ventanas con la misma disposición es posible realizarlo con un script como el siguiente.

1
2
3
4
5
6
#!/usr/bin/env bash
tmux new-session -s "Session" -d
tmux set-option -g mouse on
tmux split-window -h
tmux split-window -v
tmux attach-session -t "Session"

En el manpage de tmux y los enlaces de referencia hay guías con una lista más completa que las operaciones básicas que incluyo en este artículo.

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

La Edad de Oro del software español

octubre 04, 2019 10:25

Hubo una década, que durante diez años, entre 1982 y 1992, España se convirtió en el segundo desarrollador de sofrware a nivel mundial, precedido solamente por el Reino Unido. En ambos países, aquello resultó ser una sorpresa imprevista, puesto que durante esos años, la tecnología, tanto de hardware como de software estaba en manos de …

La Edad de Oro del software español Leer más »

Artículo publicado originalmente en Bitácora de Javier Gutiérrez Chamorro (Guti)

La entrada La Edad de Oro del software español aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

» Leer más, comentarios, etc...

Picando Código

Humble Book Bundle: ebooks de Linux & UNIX por O’Reilly

septiembre 30, 2019 09:00

Humble Bundle tiene un nuevo paquete de e-books sobre Linux, Unix y varias herramientas muy útiles del entorno. Los ebooks están disponibles en PDF, ePUB y MOBI, por lo que pueden ser leídos en casi cualquier dispositivo. Como se acostumbra en los paquetes Humble Bundle, además de elegir el precio, podemos elegir dónde destinamos el dinero que pagamos, incluyendo una organización de beneficencia.

Humble Book Bundle: Linux & Unix por O'Reilly

Tengo el “Mastering Regular Expressions” que compré hace años. Me sirvió mucho en su momento para ampliar mi conocimiento y uso de expresiones regulares. Tengo idea que varios libros más del paquete o compré o leí por ahí. Están todos sumamente interesanes y creo que me voy a comprar el paquete para tenerlos en formato digital portátil. Son herramientas que uso seguido y siempre estoy atento a aprender más.

Pagando USD 1 o más, obtenemos:
Classic Shell Scripting, Linux Device Drivers, Introducing Regular Expressions, grep Pocket Reference, Learning GNU Emacs y Unix Power Tools.

Por USD 8 o más, todos los anteriors y:
Learning the bash shell, Learning the vi and Vim Editors, Linux in a Nuthsell y sed & awk.

Por último por USD 15, todo lo anterior más:
bash Cookbook, Linux System Programming, Mastering Regular Expressions, Effective awk Programming y Linux Pocket Guide.

Comprar el paquete de libros

» Leer más, comentarios, etc...

Coding Potions

Introducción a VueJS ≫ Qué es y sus características

septiembre 27, 2019 12:00

Introducción

Bienvenido al primer capítulo de una serie de artículos que voy a escribir sobre VueJS. Mi principal finalidad de esta serie es que aprendas a usar VueJS de manera profesional. Voy a intentar enseñarte todos los consejos y funcionalidades de Vue que me hubiera gustado que me enseñaran cuando yo lo estaba aprendiendo.

Si no tienes conocimientos previos de Vue no tengas miedo porque te voy a explicar cómo funciona todo desde el principio. Lo que si que recomiendo es que tengas conocimientos sobre Javascript, HTML y CSS ya que es lo que usa Vue por debajo y lo vas a necesitar.

Pero antes de empezar manos a la obra a programar, hay que ver qué es y para que sirve Vue, cómo se instala y para qué sirve su cli y la estructura de archivos que se crea.

¿Qué es VueJS?

Logo de Vue

Vue JS como su nombre indica es un framework javascript, es decir, es un conjunto de herramientas y funciones que permiten desarrollar páginas web de una manera más cómoda. Vue nace con la necesidad de no tener que escribir tanto código javascript y sobre todo con la idea de ahorrar tiempo al programador.

Vue fue creado por Evan You, ex-trabajador de Google, que decidió crear su propio framework en el año 2014. Desde entonces, Vue ha subido muchísimo de popularidad, gracias a su sencillez y a todo lo que puede ofrecer, que lo vamos a ver a continuación.

¿Para qué sirve VueJS?

Respuesta corta: Para crear páginas web completas.

Respuesta larga: VueJS es una librería javascript pensada para tener un framework con el que desarrollar páginas web. Con Vue puedes crear todas las vistas de tu página web, puedes hacerlas dinámicas, puedes conectarla a un servidor para tener datos dinámicos de una base de datos, etc.

Con Vue puedes hacer desde páginas básicas a cosas más complejas. En ocasiones se compara Vue con JQuery, pero Vue más allá. JQuery está pensado para ahorrar código javascript pero no para hacer páginas web completas (se pueden hacer pero tienes que invertir mucho tiempo). Con Vue ya no vas a necesitar Jquery y tampoco vas a necesitar otras librerías javascript.

En definitiva, Vue es un framework completo pensado para los programadores web, con buena curva de aprendizaje y que se puede usar en todo tipo de webs.

Características de Vue

Vue ofrece todo un conjunto de características y funcionalidades que permiten crear aplicaciones web completas. Si vienes de Angular o React muchas de las cosas que ofrece ya te sonarán, debido a que este framework está inspirado en estos dos.

Como es un framework, va más allá de simplemente ofrecer funciones y utilidades para Javascript. Es una nueva forma de programar páginas web. Pero no te preocupes porque con una buena base de Javascript la curva de aprendizaje no es muy grande.

Si tienes dudas sobre si merece la pena usar Angular o React o VueJS, más abajo voy a hacer una pequeña comparación entre ellos. Antes vamos a ver lo que puede ofrecer.

Modularidad

Lo primero que salta a la vista de Vue es que es completamente modular. A diferencia de Angular que está pensando para ofrecerte todo lo necesario, en Vue tienes más libertad para usar ciertas características. Por ejemplo en Angular si quieres realizar llamadas HTTP puedes usar su propio paquete dentro de Angular. En Vue si quieres realizar estas llamadas tienes que instalar por tu cuenta el paquete que prefieras, axios por ejemplo.

Es decir, mientras que otros frameworks javascript te dan todo lo que necesitas, Vue ofrece lo básico para que puedas elegir si instalar a posteriori las utilidades que necesites.

Reactividad

Vue tiene propiedades reactivas, eso quiere decir que si cambia una variable en una parte de la vista de la página, Vue actualizará su nuevo valor sin necesidad de que lo hagas manualmente. El ejemplo típico es un contador. Si lo quieres hacer en Javascript puro, tienes que actualizar el valor en la vista cada vez que incrementas el contador. En Vue basta incrementar el contador para que se actualice en la página el nuevo valor.

Para casos mucho más complejos que éste, te aseguro que vas a agradecer que Vue sea reactivo.

Componentes web

Logo componentes web

Vue se basa en componentes web. Un componente web es una parte de una web que puede ser reutilizada y que normalmente tiene estilos y funcionalidad aislada.

Si no los conocías ya seguramente te sorprendas al saber que ese concepto ya lo has utilizado si has programado páginas web. Cuando creas una etiqueta html, por ejemplo

Los componentes web básicamente, permiten crear tus propias etiquetas HTML personalizables, es decir, imagina que necesitas crear un calendario y que lo vas a usar en varias vistas de la web. Creando un calendario en forma de componente web, puedes crear calendarios simplemente creando llamando a la etiqueta que tu mismo definas para el HTML, por ejemplo: .

Los componentes web los puedes crear con javascript sin necesitar Vue, pero este framework nos va a facilitar mucho la vida y nos va a ahorrar mucho tiempo.

Virtual DOM

Si hay que hacer un cambio en la vista, en lugar de sustituir directamente los nuevos valores en la vista, Vue creará una especie de réplica del DOM, es decir, de los elementos de la página web para que a la hora de hacer cambios en la vista se hagan de forma más óptima.

Eventos y transiciones

Puedes reaccionar a eventos que se producen en el DOM, por ejemplo cuando el usuario hace click en un elemento, cuando lo mueve, cuando escribe, etc.

Otra de las cosas interesantes de Vue es su sistema de transiciones y animaciones. Es muy sencillo de usar y a la vez puede llegar a ser muy complejo. Las animaciones son las que ya conoces de CSS por lo que no tendrás que aprender sistemas nuevos.

Mixins

Los mixins son funciones y lógica de los componentes que puedes reutilizar y reusar en otros componentes web. Con los mixins puedes compartir cualquier clase de opción que le puedes pasar a los componentes.

Lifecicle (ciclo de vida) de los componentes

Como también pasa en Angular y en React, tienes control sobre todo el ciclo de vida de los componentes, es decir, puedes controlar lo que ocurre antes de que se cargue el componente, lo que pasa justo al cargarse o al destruirse. Esto es útil por ejemplo cuendo queremos que pasen ciertas cosas cuando el usuario entra en una página (por ejemplo llamar a una API REST para cargar los datos)

Aplicaciones SPA gracias a Vue Router

Vue tiene un paquete oficial para poder tener un sistema de rutas. El sistema de rutas llamado vue router, permite tener una página web SPA, es decir, todas las páginas están ya cargadas cuando el usuario entra en la página web de tal forma que cambiar de página es instantáneo. Este sistema no es único de Vue, también lo tiene Angular y React.

Vue vs React vs Angular. ¿Cuál elegir?

Lo primero, podemos comparar el tamaño de todos los frameworks (en el año 2019). Este dato no es muy comparable, ya que Angular ofrece un framework completo, y en el caso de Vue y React, vas a necesitar más librerías si quieres hacer más cosas.

  • Angular: 500+ KB
  • React: 100 KB
  • Vue: 80 KB

En cuanto a la curva de aprendizaje, en mi opinión, Angular es el más difícil de aprender. Con Angular, necesitas aprender Typescript e inyección de dependencias, que, aunque no es muy difícil, añade cierta complejidad en su aprendizaje.

React es más fácil de aprender pero su sintaxis hace que pueda resultar algo lioso para ciertas personas.

Vue en mi opinión, es el más sencillo de aprender, su sintaxis no resulta compleja y tiene una curva de aprendizaje muy asequible.

Angular y React cuentan con el apoyo de una gran compañía. Google en el caso de Angular y React en el caso de Facebook. VueJS no tiene apoyo de grandes compañías, solo de la comunidad, pero si que hay empresas que han desvelado que utilizan Vue como framework en proyectos importantes (Apple, Nike, etc).

Veamos ahora las ventajas de cada uno de ellos en cuanto a lo que puede ofrecer:

Ventajas de Angular:

Logo de Angular

  • Typescript. Aunque al principio cueste más al tener que aprender su sintaxis, al final hace que se tengan menos errores en aplicaciones grandes al poder usar tipado e interfaces.
  • Framework completo. A posteriori no vas a tener que instalar nada nuevo. Viene con todo para crear aplicaciones web completas.
  • MCV. Modelo vista controlador que permite tener los datos separados de la lógica y de su representación
  • Inyección de dependencias. Permite testear mejor los componentes ya que puedes crear mocks de las dependencias. Además permite modularizar mejor el código y abstraerse de los detalles de implementación de las dependencias.
  • Arquitectura muy bien pensada para proyectos grandes. Todo está bien separado y organizado. Esto en proyectos pequeños puede resultar una desventaja porque es más lioso y necesitas más archivos.
  • Servicios. Es una funcionalidad que trae Angular para poder abstraerse de las llamadas a la adquisición de los datos. Puedes tener las llamadas a una API, por ejemplo, en archivos separados que puedes inyectar en los componentes.

Ventajas de React:

Logo de React

  • Tiene una comunidad detrás muy importante. Si tienes algún problema seguramente haciendo una búsqueda en google llegues a solucionarlo ya que a otro programador le habrá pasado lo mismo que a ti.
  • A diferencia de Angular, React no viene con todo un set de utilidades ya creadas. Esto permite que sea mucho más flexible ya que puedes usar o implementar lo que necesites sin necesidad de usar lo que te dan. Esta ventaja también la ofrece Vue.
  • React native. Con esta librería vas a poder crear aplicaciones móviles nativas con React de forma que sin tener que cambiar mucho, puedes crear una web y una aplicación móvil.
  • Si te gusta programar en Javascript con React te vas a sentir bastante cómodo. Aunque Vue también se usa con Javascript, React utiliza javascript para el html y los estilos.

Ventajas de Vue:

Logo de Vue

  • Curva de aprendizaje. En mi opinión y en la de muchos programadores, tardas menos tiempo en aprender los básico para poder desenvolverte con el framework.
  • Arquitectura limpia. Por como está hecho Vue, el código de los componentes queda mucho más ordenado y limpio.
  • Archivos .vue. A diferencia de React con sus archivos jsx, en los archivos vue puedes escribir html y css sin tener que hacerlo dentro de javascript. Está todo perfectamente separado.
  • Comunidad en crecimiento. Aunque Vue no tiene una comunidad tan grande como React y Angular, su comunidad ha tenido un crecimiento espectacular en los últimos tiempos y se según las encuestas va a ir a más.

Yo personalmente pienso que Angular está más enfocado a aplicaciones web grandes, con una estructura muy compleja. Vue y React son más parecidos, la sintaxis de React no me acaba de convencer y si tengo que escoger un framework me quedaría con Vue.

Cómo instalar Vue. Hello world

Bien, si ya te has decidido a utilizar Vue, lo primero es ver cómo se puede crear un proyecto con este framework javascript. Se puede hacer de varias formas:

Con Vue CLI

La opción que yo siempre suelo usar. Vue CLi es una herramienta para línea de comandos que sirve para gestionar proyectos Vue. Para usarla puedes descargarla en tu equipo desde su paquete NPM:

npm install -g @vue/cli

Para que el vue cli se encarge de crear toda la estructura inicial del proyecto ejecuta:

vue create nombre-de-tu-proyecto

Cuando ejecutas ese comando, la terminal te preguntará si quieres las opciones por defecto o quieres personalizarlo

Cómo crear un proyecto con Vue CLI

Si no sabes qué elegir le puedes dar a la opción default, no te preocupes porque todo se puede añadir al proyecto después de haber sido creado. En cuanto le des a esta opción se creará el proyecto y no tendrás que hacer nada más. Las opciones que voy a comentar ahora son por si seleccionas la opción manual.

Si decides manualmente seleccionar las opciones que prefieres, se abrirá otra pantalla en la que podrás instalar algunos paquetes básicos (yo suelo seleccionar vuex para gestionar estado, vue router para poder crear rutas en la web y css preprocessors porque me gusta usar sass). Puedes seleccionar los que quieras a tu gusto con la tecla espacio.

Qué opciones tiene Vue CLI

En la siguiente pantalla aparecerá que tipo de configuración quieres para el eslint, es decir, para el linter que analiza el código en busca de errores. Yo suelo escoger prettier. Luego te saldrá si quieres ejecutar el eslint cada vez que guardas y cada vez que haces commit. Yo recomiendo poner las dos opciones para evitar errores en el código.Lint on sa

La siguiente pantalla te dice si quieres la configuración en el package.json o en archivos dedicados. Yo recomiendo en archivos dedicados para tener todo separado en su lugar.

Yo para esta serie de artículos voy a escoger estas opciones para generar el proyecto de Vue:

  • Babel, Router, CSS Pre-processors, Linter / Formatter
  • History mode: yes. Si pones que no lo que va a hacer Vue es añadir al final de cada ruta un hash (#) para que el navegador no recargue la página al navegar entre ellas
  • Sass / Scss with dart-sass. A mi me gusta sass. Uso dart-sass porque a veces node-sass da problemas.
  • EsLint + Prettier. Es la opción que más me gusta para el linter
  • Lint on save y lint and fix on commit. Muchas veces me ha salvado de subir código con errores
  • Dedicated config files. Más fácil de mantener.

Por último te preguntará si quieres guardar estas opciones para crear proyectos en el futuro y se creará el proyecto.

Importando la librería de Vue

La otra forma de hacerlo, ideal cuando estamos haciendo algo simple o queremos prototipar rápido, consiste en usar directamente el javascript compilado de Vue de forma local o mediante CDN:

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

Importando la librería de Vue ya tienes acceso a la variable global de Vue. Aquí te dejo un ejemplo de un hello world con vue con este método:

https://jsfiddle.net/chrisvfritz/50wL7mdz/

Mediante codesanbox o similares

Existen en Internet páginas gratuitas como codesanbox que permite crear proyectos de Vue. Cuando lo creas, te abre un editor de código online con vista previa por si no quieres instalar nada y quieres hacer pruebas en la nube.

https://codesandbox.io/

Vue CLI. El asistente de línea de comandos de Vue

Vue CLI es una librería que permite usar comandos en la consola del ordenador para automatizar ciertas tareas. Este CLI es muy parecido al que tiene Angular o el que tiene React, es muy recomendable su uso en el día a día para ahorrar tiempo.

Si todavía no has instalado vue cli te vuelvo a dejar el comando:

npm install -g @vue/cli

Si al ejecutar uno de los comandos el asistente te dice que tienes que instalar un addon, ejecuta:

npm install -g @vue/cli-service-global

Veamos los comandos y todo lo que puede ofrecer vue cli:

Serve. Desarrollo en local

vue serve

Sirve para ejecutar la página en local para que puedas ver los cambios mientras desarrollas. Lo bueno de este comando es que tiene hot reloading es decir, cuando haces un cambio en uno de los archivos de vue (excepto en los de configuración globales), se actualiza la página sin necesidad de recargar.

Otra forma de ejecutar este comando, si has creado el proyecto con vue create es mediante el script que se crea en el package.json. Es decir:

npm run serve

Si usas el primer comando lo tienes que hacer dentro de la carpeta src del proyecto y si usas el segundo comando lo tienes que hacer en la carpeta en la que esté el package.json.

Una vez ejecutado el comando, y cuando haya cargado, si abres el navegador en la página http://localhost:8080 podrás ver la página que estás desarrollando. Lo tienes que dejar ejecutándose meintras desarrollas para ver los cambios.

Build. Compilación de tu aplicación web

vue build

El comando build sirve para compilar los archivos para ponerlos en producción, es decir, sirve para poder desplegar vue en un servidor.

Este comando generará todos los archivos javascript compilados y minificados para que los usuarios finales puedan acceder a la página que estás desarrollando. Para ello necesitas un hosting en el que poder usar apache o nginx.

Como el comando anterior, este comando también lo tienes disponible en el package.json.

npm run build

Este comando si que recomiendo tirarlo desde npm porque en el servidor en el que vayas a desplegar la página lo más normal es que tengas npm, así no tienes que instalar el paquete de vue cli.

Vue UI. Interfaz gráfica para administrar proyectos Vue

vue ui

Este comando sirve para ejecutar una interfaz gráfica para poder administrar los proyectos de Vue. Si no te gusta mucho andar con comandos,puedes usar esta interfaz para trabajar de manera más cómoda.

Con esta interfaz puedes crear proyectos de Vue como con el vue create, puedes administrar los que ya tienes, ejecutar desde ahí los proyectos y compilarlos y instalar de forma más cómoda dependencias.

Interfaz gráfica de Vue UI

Añadir plugins con Vue CLI

Si después de haber creado un proyecto con Vue decides instalar una librería que no habías puesto, con este comando vas a poder hacerlo sin tener que configurar nada, por ejemplo:

vue add router

O por ejemplo:

vue add @vue/cli-plugin-eslint

Lo bueno de este comando es que ya te configura los archivos que tenías para añadir la configuración de los nuevos plugins. Si estos mismos paquetes los instalas mediante npm, vas a tener que añadir manualmente su configuración en cada archivo.

Herramientas recomendadas para programar con Vue

Vue tiene un tipo de archivos específico, los .vue y por lo tanto cuando los abras en cualquier IDE o programa no te va a pintar de colores la sintaxis como en otros lenguajes, por lo tanto necesitas instalar plugins en el IDE o editor de texto que utilices.

Editor de texto recomendado para Vue

El editor que yo siempre recomiendo para trabajar con Vue es el VSCode. No solo lo uso para programar en Vue si no que también lo uso para cualquier lenguaje para el frontend, incluso para python.

Te dejo su página web por si te lo quieres descargar. Por cierto, es gratuito y open source.

https://code.visualstudio.com/

Para VSCode existe un plugin ideal para Vue, llamado Vetur. Instalando este plugin vas a tener todo lo necesario para usar Vue en vscode. Este plugin va a hacer que tengas la sintaxis de colores, te va ayudar con el lint y formateado de archivos, tiene autocompletado, snippets, etc.

Para instalarlo puedes buscarlo en la sección Extensions (el último icono del menú de la izquierda).

Vetur, la mejor extensión de Vue CLI

Además, te recomiendo que crees un archivos llamado .editorconfig en la raíz del proyecto con estas opciones:

root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

Este fichero lo que hace es decirle al editor, en este caso al vscode que las tabulaciones sean de dos espacios para cuando creemos los archivos de vue.

Para que funcione te tienes que descargar esta extensión para que el vscode lea el archivo:

https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig

Otros plugins para trabajar con Vue

Conclusiones

Vue, en mi opinión, es uno de los mejores frameworks para el frontend del panorama actual. Es simple, se aprende rápido su estructura es limpia y su comunidad va en aumento.

Con lo que hemos visto hoy deberías tener una idea básica de qué es Vue y como crear la estructura de tu primer proyecto con Vue.

Si te sientes perdido es normal, nos pasa a todos al principio. Te recomiendo que sigas los próximos capítulos de esta serie sobre Vue. Próximamente veremos cómo empezar a programar en Vue y cómo se organiza un proyecto Vue.

» Leer más, comentarios, etc...

proyectos Ágiles

¿Para qué Agile?

septiembre 24, 2019 08:45

[See this article in English here]

En mi vida profesional ha habido siempre dos lemas importantes: (1) cuál es el “para qué” de lo que se hace y (2) la gente ha de estar “bien” (porque si las personas no están suficientemente motivadas no se puede hacer bien el para qué y, en el peor de los casos, la gente marcha). Consiguientemente, el objetivo de mi trabajo ha sido ayudar a empresas a ser más “Ágiles”, y así todos contentos (ellas y yo). Sin embargo, en los últimos años notaba que algo no acababa de encajar: ¿cuál es el impacto real del “para qué”?

En los últimos decenios todo ha ido cambiando a un mundo cada vez más acelerado, más inmediato, de reacción instantánea… ¿Es esto una sociedad más Ágil?

¿Somos conscientes de lo que estamos “transformando”, de cómo lo que hacemos influye en los comportamientos de las personas? Cada vez la humanidad parece más cortoplacista, impulsiva, con menor capacidad de reflexión. Me da la sensación de que estamos amplificado nuestro instinto animal de depredar al máximo rápidamente, como si no se supiese qué va a pasar en unas horas, como si no hubiese un mañana. Todo es más frío, menos cálido, menos… humano. Eso sin contar con el impacto en las personas a las que sometemos a ser “extensiones de maquinaria” en la cadena productiva, desde la propia producción hasta la entrega en la puerta de nuestra casa, todo tiene que ser para conseguir lo que sea de manera inmediata, con el mínimo esfuerzo… creando también una cultura que ya no valora las cosas ni el esfuerzo para conseguirlas, sin crear interés en lo que realmente “cuestan” de verdad, no sólo a nivel personal sino en global.

A las personas que trabajamos en agilidad organizativa nos gusta pensar de manera sistémica, holística, trabajando la cadena de valor de las compañías. Sin embargo, en estos últimos meses, no deja de aparecer cada vez más información sobre las “entradas” y “salidas” completas de la sociedad en que vivimos (todas ellas MUY relacionadas): calentamiento global, superpoblación, incencios gigantescos (Amazonas, Siberia, Indonesia, …), falta de recursos naturales, tensiones geoestratégicas, despilfarro (mentalidad de “usar y tirar” que hace que muchos bienes acaben rápidamente en vertederos), comer menos carne (ONU), océanos esquilmados y llenos de plástico, …

Entonces, ¿para qué Agile? ¿Para comernos el planeta cinco veces más rápido, cubriéndolo de desperdicios y reduciendo a millones de personas a extensiones de maquinaria?

¿Qué daño/dolor estamos infligiendo ahora mismo y para el futuro? ¿Qué tipo de inestabilidades van a venir a nivel global? ¿De verdad que como especie y sociedad no podemos ir más allá y hacer cosas más trascendentes, que impliquen progreso pero sin dejarlo todo destrozado para futuras generaciones (y destrozándolas a ellas en el futuro!!)? A mí no me gustaría que dentro de unos años mis hijas o su descendencia dijesen que mi generación, que tuvo los datos en la mano, fue la mayor cómplice y miró hacia un lado.

Creo que todos los sistemas tienden a un equilibrio, mucho más abajo, duro y diferente si todo se hizo de manera insostenible. Por ello, es crucial intentar gestionar ese equilibrio… o él te gestionará a ti (de manera abrupta y mucho más dolorosa, como fue hace unos años la crisis financiera-inmobiliaria que todavía sufrimos).

 “Free fall through our midnight / This epilogue of our own fable” (…) “Drifting through this boundlessness / This madness of our own making” (…) “Sound the reveille / To be or not to be / Rise / Stay the grand finale / Stay the reading of our swan song and epilogue

No alt text provided for this image

 En la conferencia anual de Agile Spain del año pasado estuve conversando al respecto con una de las Keynotes, Lyssa Adkins. Me comentó que había bastante gente del mundo Agile que, como yo, era consciente de esa disonancia: trabajamos para que las empresas aceleren el nivel de consumo de sus productos pero eso puede tener un impacto global no positivo. Me quedé más tranquilo (“así pues, no soy demasiado raro”) pero con poco más que una constatación.

En los principios del Agile Manifesto se habla del desarrollo a un paso sostenible y de la motivación de la gente, es decir, cuando se escribió un aspecto importante era no quemar a las personas. Creo que hay que ampliar ese concepto de sostenibilidad y hablar de un Agile sostenible que también considere todos los byproducts de las empresas, con una visión más holística: no “quemar” a las personas y tampoco a la sociedad y el planeta.

Ahora es el momento de aprovechar la Agilidad para hacer un cambio de ciclo, porque necesitamos que sea rápido y utilizar todo nuestro conocimiento para darle la vuelta.

En mi caso, esto ha implicado reconsiderar un principio que hasta ahora se habían quedado en lo más personal y subirlo al nivel profesional: mi lema adicional (3) va a ser trabajar para que, allí donde yo esté, el propósito de la empresa sea sostenible, para que su modelo de negocio sea rentable dejando un balance positivo en el global (empleados, sociedad y ecosistema). Crear/comprar bienes que duren y que sean reciclables para que el sistema sea auto-sostenible (reduciendo así los “pulls” al planeta), aumentar la dignidad de los trabajos de las personas, crear consciencia, educar e intentar cambiar el mindset que nos ha llevado hasta aquí.

Y esto va de todos nosotros, podemos hacer muchas cosas. Si has llegado a leer hasta aquí, es probable que esto también sea importante para ti, seguro que hay alguna cosa que tú puedes hacer, aunque sea pequeña, para este balance en positivo que necesita crear la humanidad 🙂

“One drive to stay alive / It’s elementary / Muster every fiber / Mobilize / Stay alive”

[See this article in English here]

» Leer más, comentarios, etc...

Fixed Buffer

Como medir el rendimiento de nuestro código

septiembre 24, 2019 08:00

La imagen muestra un medidor de velocidad para el entrada "Como medir el rendimiento de nuestro código"

A raíz de las entradas sobre la serie de entradas sobre la reflexión que publicamos antes del parón de verano, he estado escribiéndome con un lector sobre algunas posibles optimizaciones en el código, todas ellas midiendo el rendimiento del código para ver cuál era mejor. Llevaba tiempo queriendo escribir sobre este tema, ¿y que mejor momento qué ahora? 🙂

¿Cómo se mide el rendimiento del código?

Para conseguir datos que nos sirvan para esto, se utilizan pruebas de rendimiento o «benchmarks», los cuales nos van a servir para obtener las métricas que vamos a comparar (tiempo, cpu consumida, ram utilizada…) para decidir si nuestro código tiene el rendimiento esperado. Normalmente, esto se consigue midiendo los datos a comprobar y ejecutando el código un número suficiente de veces para asegurar que los posibles «ruidos externos» no afectan a las métricas.

Imagina que simplemente medimos el tiempo de ejecución de método ejecutándolo solo una vez, cualquier cosa que el sistema operativo ejecute podría falsear los resultados…

En el ecosistema .Net, existe una librería que se distribuye a través de NuGet que nos facilita enormemente esta labor, y es de la que os voy a hablar ahora, esta librería es BenchmarkDotNet, Vamos a ponernos en faena:

Como usar BenchmarkDotNet

Vamos a imaginar que dentro de nuestro código tenemos algo como esto:

public class OperacionesMatematicas
{
    public double Suma(double a, double b)
    {
        return a + b;
    }

    public double Multiplicacion(double a, double b)
    {
        return a + b;
    }

    public double Potencia(double @base, double exponente)
    {
        return Math.Pow(@base, exponente);
    }

    public double Potencia2(double @base, double exponente)
    {
        if (exponente == 0)
            return 1;

        var resultado = @base;
        for (int i = 1; i < exponente; i++)
        {
            resultado = resultado * @base;
        }
        return resultado;
    }
}

Simplemente es una clase que va a hacer ciertas operaciones matemáticas, teniendo además dos maneras de calcular una potencia, utilizando Math.Pow y multiplicando la base por si misma tantas veces como indica el exponente (lo que es una potencia vamos…).

Lo primero que vamos a necesitar para medir el rendimiento de nuestro código, es crear un proyecto de consola que será el que tenga el código para las pruebas, en este caso, lo voy a llamar «BenchmarkRunnerProject». A este proyecto le vamos a añadir el paquete «BenchmarkDotNet«, y vamos a crear una clase donde vamos a añadir la lógica de la prueba:

public class OperacionesMatematicasBenchmark
{
    [Benchmark]
    public void Suma()
    {
        var operaciones = new OperacionesMatematicas();
        operaciones.Suma(10, 20);
    }

    [Benchmark]
    public void Multiplicacion()
    {
        var operaciones = new OperacionesMatematicas();
        operaciones.Multiplicacion(10, 20);
    }

    [Benchmark]
    public void Potencia()
    {
        var operaciones = new OperacionesMatematicas();
        operaciones.Potencia(2, 2);
    }

    [Benchmark]
    public void Potencia2()
    {
        var operaciones = new OperacionesMatematicas();
        operaciones.Potencia2(2, 2);
    }
}

Por último, solo nos queda añadir al método Main la ejecución de las pruebas:

class Program
{
    static void Main(string[] args)
    {
        var summary = BenchmarkRunner.Run<OperacionesMatematicasBenchmark>();
        Console.Read();
    }
}

Una vez hecho esto, ya solo necesitamos ejecutar el proyecto para que nuestra prueba funcione. Pero ojo, tiene que estar en «Release» para poder medir el rendimiento del código con las optimizaciones del compilador. En caso contrario, nos mostrará un mensaje indicándonos que lo hagamos o desactivemos que tenga que ser Release:

La imagen muestra la salida de la consola cuando ejecutamos un benchamrk sin estar en release

Una vez que se ejecute, nos mostrará los resultados en la propia consola:

La imagen muestra un ejemplo de la salida básica

Con esto, ya tenemos la funcionalidad básica, donde solo medimos el tiempo de ejecución con los parámetros que hemos puesto «hardcoded». Pero tenemos la opción de indicar diferentes parámetros con el atributo «Params»:

public class OperacionesMatematicasBenchmark
{
    [Params(2, 3)]
    public int A { get; set; }

    [Params(2, 200)]
    public int B { get; set; }

    [Benchmark]
    public void Suma()
    {
        var operaciones = new OperacionesMatematicas();
        operaciones.Suma(A, B);
    }

    [Benchmark]
    public void Multiplicacion()
    {
        var operaciones = new OperacionesMatematicas();
        operaciones.Multiplicacion(A, B);
    }

    [Benchmark]
    public void Potencia()
    {
        var operaciones = new OperacionesMatematicas();
        operaciones.Potencia(A, B);
    }

    [Benchmark]
    public void Potencia2()
    {
        var operaciones = new OperacionesMatematicas();
        operaciones.Potencia2(A, B);
    }
}

Con este cambio, vamos a conseguir que se ejecute una prueba con cada una de las configuraciones:

La imagen muestra los resultados de la ejecución son parametros

E incluso ordenarlas si añadimos el atributo «RankColumn» a la clase:

La imagen muestra el resultado con el atributo rankcolum

Existen muchísimas opciones y parametrizaciones que pueden servirte para configurar cada uno de los aspectos del benchmark, e incluso comparando la ejecución en diferentes entornos (.Net Framework, .Net Core, Mono) y diferentes versiones de los entornos. Te recomiendo que le eches un ojo a la documentación para ver todas las opciones disponibles, ya que, es imposible hablar de todas ellas en una única entrada. (Por ejemplo, para medir la RAM con Diagnosers).

Como siempre, dejo el enlace al repositorio en GitHub con el código de la entrada.

**La entrada Como medir el rendimiento de nuestro código se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Fixed Buffer

¡¡.Net Core 3 ya esta disponible!!

septiembre 23, 2019 09:10

La imagen  muestra el nuevo layout de funciones de .Net Core 3

¡¡El ansiado día ha llegado!!. Por fin esta disponible para descarga pública la versión final de .Net Core 3 y de su mano .Net Standard 2.1 y C# 8.0. Puedes seguir el evento en directo aquí.

Durante las próximas semanas hablaremos sobre las muchas novedades que trae para hacer más fácil el cambio (formularios, índices, enumeraciones asíncronas…).

¡¡Se deparan unas semanas apasionantes descubriendo las mejoras que nos trae esta nueva versión del .Net!!

**La entrada ¡¡.Net Core 3 ya esta disponible!! se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin