Quantcast
Channel: Planeta Código
Viewing all 2726 articles
Browse latest View live

Blog Bitix: Buscar en el historial desde la barra de direcciones inteligente de Firefox

$
0
0
Firefox

Los navegadores web guardan un historial de todas las páginas a las que se acceden, además de los marcadores que los usuarios creen. Este historial en Firefox se guarda en orden cronológico pudiendo consultar todas las páginas accedidas en el día actual, el de ayer y anteriores fechas. También es posible realizar búsquedas para encontrar una cierta página. En Firefox al historial se accede desde en menú con la opción Historial > Mostrar todo el historial. El historial se muestra en una ventana.

Historial de páginas en Firefox

Acceder al historial requiere abrir una ventana y luego hacer una búsqueda pero sin necesidad de abrir la ventana del historial desde la barra de direcciones inteligente también pueden hacerse búsquedas, no solo para las páginas del historial sino también entre los marcadores, pestañas abiertas, por títulos de página o por coincidencias en la dirección web. Con ciertos caracteres especiales se determina el comportamiento de la búsqueda.

  • ^: para buscar coincidencias en el historial de búsqueda.
  • *: para buscar coincidencias en los marcadores.
  • +: para buscar coincidencias en las etiquetas de las páginas.
  • %: para buscar entre las pestañas abiertas actualmente.
  • #: Para buscar coincidencias en usando los títulos de página.
  • $: para buscar coincidencias en la dirección web.

En esta captura de hace una búsqueda por el título de las páginas en el historial.

Barra de búsqueda inteligente de Firefox

Blog Bitix: Generar documentos, informes y facturas en formato PDF con JasperReports y Java

$
0
0

Para generar documentos PDF sencillos en Java está la librería PDFBox que mediante código permite insertar la información y los elementos del documento. Con PDFBox el documento es generado completamente mediante código, para separar el estilo del documento y la información que contiene y para documentos más complejos está JasperReports que mediante una plantilla hace que si cambia el estilo del documento el código no requiera cambios.

Java

Las aplicaciones en el ámbito de gestión necesitan generar documentos a partir de la información que contienen. Pueden ser para exportar datos en un archivo en formato CSV con Apache POI o documentos PDF sencillos con PDFBox. Los documentos PDF pueden ser de diverso tipo, informes, facturas, cartas, recibos, … En Java una de las librerías para generar documentos PDF complejos es JasperReports.

Los informes de JasperReports se generan a partir de una plantilla creada con JasperReport Studio. JasperReports divide un documento en diferentes bandas en las cuales se puede incluir diferentes elementos como texto, valores, imágenes, … Las bandas son apartados de información como la cabeceras o detalles, puede estar anidadas y repetirse según los datos de la fuente de datos.

JasperSoft Studio

Los informes con JasperReports tiene varias posibilidades de obtener los datos, una de ellas es proporcionándoselos mediante parámetros y o una colección de beans de cualquier tipo, pero también proporcionándole una conexión a la base de datos relacional y que JasperReports lance consultas SQL para obtener los datos que necesita.

Utilizando los elementos de la paleta como campos de texto e imagen y posicionándolos en el lugar adecuado sobre el informe se crea la plantilla del documento. Para asignar valores a los elementos se inserta una expresión que en este caso permite obtenerlo de los parámetros que se le proporcionen al informe a los cuales con funciones incorporadas se les puede aplicar transformaciones para obtener el valor deseado (de fecha, lógicas, numéricas o de texto).

Editor de expresiones

El código Java necesario para compilar el archivo de la plantilla del informe, proporcionarle los parámetros y generar el PDF es el siguiente.

 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
packageio.github.picodotdev.blogbitix.jasperreports;importnet.sf.jasperreports.engine.JasperCompileManager;importnet.sf.jasperreports.engine.JasperExportManager;importnet.sf.jasperreports.engine.JasperFillManager;importnet.sf.jasperreports.engine.JasperPrint;importnet.sf.jasperreports.engine.JasperReport;importnet.sf.jasperreports.engine.data.JRBeanCollectionDataSource;...publicclassMain{publicstaticvoidmain(String[]args)throwsException{Map<String,Object>parameters=newHashMap<String,Object>();Facturafactura=newFactura("Compañía S.A.","picodotdev","Factura enero 2019","100000","00011111111",newBigDecimal("25.00"),"1111111","picodotdev","BASKESXXXX","ES24-0000-0000-0000-0000-0000",LocalDateTime.now(),LocalDateTime.now());List<Factura>facturas=Arrays.asList(factura);InputStreamis=Main.class.getResourceAsStream("factura.jrxml");JasperReportreport=JasperCompileManager.compileReport(is);JRBeanCollectionDataSourcedataSource=newJRBeanCollectionDataSource(facturas);JasperPrintprint=JasperFillManager.fillReport(report,parameters,dataSource);JasperExportManager.exportReportToPdfFile(print,"factura.pdf");}}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
plugins{id'java'id'application'}application{mainClassName='io.github.picodotdev.blogbitix.jasperreports.Main'}dependencies{implementation'net.sf.jasperreports:jasperreports:6.11.0'implementation'com.lowagie:itext:2.1.7'}repositories{mavenCentral()}

El resultado es este boceto de factura a la que con más tiempo, añadiendo más elementos y modificando los estilos quedará algo más real a lo que son las facturas emitidas por las compañías.

Documento PDF generado con JasperReports

En este caso los datos solo se proporcionan mediante parámetros pero JasperReport también es capaz de extraer los datos realizando consultas en a la bases de datos directamente usando una conexión de JDBC y las sentencias SQL adecuadas. En algún caso también es posible insertar en el documento una gráfica generada con JFreeChart previamente, al informe como parámetros se le puede enviar cualquier tipo de Java que para una gráfica es un InputStream.

Los siguientes enlaces son documentación a una guía de inicio, una guía completa y tutoriales.

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 ./gradlew run.

Variable not found: Enlaces interesantes 384

$
0
0
Enlaces interesantes
Ahí 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.

Variable not found: Streaming en gRPC, parte II: Streaming bidireccional

$
0
0
gRPC logo
Días atrás veíamos lo sencillo que resultaba crear un servicio gRPC que hacía uso de streaming unidireccional de mensajes, en sentido servidor-cliente. Como recordaréis, en este post implementábamos un servicio generador de números al que los clientes podrían conectarse para recibir una secuencia de enteros a intervalos periódicos.

Servicio de streaming unidireccional en ejecución

Hoy vamos a complicar algo el escenario, pues veremos una opción aún más potente: la creación de streaming bidireccional, es decir, cómo cliente y servidor pueden enviar mensajes al lado opuesto de forma asíncrona, una vez establecida la comunicación entre ambos.

Para ello, implementaremos un sencillo juego, con las siguientes funcionalidades:
  • El lado cliente, una aplicación de consola, abrirá una conexión con el servicio. En ese momento, el servidor elegirá un número al azar (1-100) y lanzará un mensaje de bienvenida, que deberá ser mostrado en el lado cliente.
  • Desde el lado cliente solicitaremos al usuario un número entero, que enviaremos al servidor por el stream ascendente.
  • El servidor recibirá el número y lo comparará con el que tiene almacenado, enviando por el canal descendente el resultado de la comparación.
  • El proceso finalizará cuando el número sea encontrado.

Implementación del lado servidor

Lo primero que vamos a hacer, tras crear el proyecto partiendo de la plantilla para servicios ASP.NET Core gRPC, en primer lugar le añadiremos el contrato protobuf del servicio a implementar en el archivo Protos/NumberGenerator.proto, con el siguiente contenido:
option csharp_namespace = "DemoGrpc";

service GuessGame {
rpc Guess(stream Number) returns (stream Response);
}

message Number {
int32 value = 1;
}

message Response {
bool found = 1;
string message = 2;
}
La implementación del servicio la haremos, como de costumbre, heredando de la clase autogenerada GuessGame.GuessGameBase y sobrescribiendo el método Guess() con el bucle principal de nuestro juego en el lado servidor:
public class GuessGameService : GuessGame.GuessGameBase
{
public override async Task Guess(
IAsyncStreamReader<Number> requestStream,
IServerStreamWriter<Response> responseStream,
ServerCallContext context)
{
var numberToGuess = new Random().Next(1, 101);
var round = 0;

var response = new Response { Message = "Hey, guess a number between 1 and 100!" };
await responseStream.WriteAsync(response);

await foreach (var number in requestStream.ReadAllAsync())
{
round++;
if (number.Value < numberToGuess)
{
response.Message = $"My number is greather than {number.Value}";
}
else if (number.Value > numberToGuess)
{
response.Message = $"My number is less than {number.Value}";
}
else
{
response.Found = true;
response.Message = $"Hey, you found the number {number.Value} in {round} rounds!";
}
await responseStream.WriteAsync(response);
}
}
}
Fijaos que principalmente se trata de ir leyendo los mensajes enviados desde el cliente a través del stream ascendente (requestStream) y utilizar responseStream para enviar el resultado de la comprobación y un mensaje de ayuda. El bucle finalizará cuando desde el cliente se dé por finalizada la petición.

Implementación del lado cliente

En el lado cliente tenemos que jugar un poco con paralelismo. Por un lado, tendremos un hilo recibiendo y mostrando por consola los mensajes recibidos desde el servidor, y por otro implementaremos el bucle principal desde el que solicitamos el número al usuario y los enviamos por el stream ascendente para que sea comprobado:
class Program
{
static async Task Main(string[] args)
{
var channel = GrpcChannel.ForAddress("https://localhost:5001");

var client = new GuessGame.GuessGameClient(channel);
using (var stream = client.Guess())
{
var found = false;

var readTask = Task.Run(async () =>
{
await foreach (var response in stream.ResponseStream.ReadAllAsync())
{
Console.WriteLine(response.Message);
if (response.Found)
{
found = true;
}
}
Console.WriteLine("Game finished, enter to exit");
});

while (!found)
{
Console.Write("> ");
var ns = Console.ReadLine();
if (!found && int.TryParse(ns, out var number))
{
await stream.RequestStream.WriteAsync(new Number { Value = number });
}
}

await stream.RequestStream.CompleteAsync();
await readTask;
}
Console.WriteLine("Press a key to close");
Console.ReadKey();
}
}
Como podéis observar, el bucle de envío de números finaliza cuando acertamos el número "pensado" por el servidor. En ese momento, damos por completada la petición con CompleteAsync() y esperamos a que la tarea en segundo plano finalice para evitar problemas.

La siguiente captura de pantalla muestra el sistema en funcionamiento:

Stream gRPC bidireccional

Y con esto, damos por finalizada esta miniserie sobre streaming con gRPC, donde hemos visto cómo esta tecnología nos permite mucha más flexibilidad a la hora de enviar y recibir mensajes que los servicios REST/HTTP tradicionales.

Espero que os haya resultado interesante y útil para aplicarlo en vuestros proyectos. Pero ojo, antes de lanzaros a implementar servicios gRPC como posesos, recordad que estos servicios no pueden ser consumidos por cualquier tipo de sistema de forma directa (por ejemplo, los browsers aún no lo soportan) y que tampoco pueden ser desplegados en algunos entornos (como IIS o Azure App Services).

Publicado bidireccionalmente en Variable not found.

Fixed Buffer: Novedades de C#8: Interfaces. ¿Qué podemos esperar?

$
0
0
La imagen muestra el logotipo de c# 8.0 para la entrada de interfaces

Llegamos a la última entrada del año y es el momento de acabar con las novedades «grandes» que nos ha introducido C#8 hablando de las interfaces. En entradas anteriores hemos hablado de Índices y Rangos, del nuevo Pattern Matching y de IAsyncEnumerable que aunque no son las únicas novedades que trae C#8, sí son las más grandes (a mi humilde criterio siempre).

Esta quizás sea una entrada controvertida y es que este cambio no ha gustado a todos por igual en la comunidad.

¿Qué es una interfaz?

Hasta ahora cuando hablábamos de una interfaz nos estábamos refiriendo a un «contrato» que incluía una serie de métodos que toda clase que la implementase se comprometía a cumplir (o de lo contrario se genera un error de compilación).

public interface IVehiculo
{
    void Avanzar();
    void Girar(int grados);
}

public class Coche : IVehiculo
{
    public void Avanzar()
    {
        //....
    }

    public void Girar(int grados)
    {
        //....
    }
}

public class Bicicleta : IVehiculo
{
    public void Avanzar()
    {
        //....
    }

    public void Girar(int grados)
    {
        //....
    }
}

Precisamente este «contrato» nos daba la capacidad de trabajar abstrayéndonos completamente de que había por debajo al utilizar la interfaz. Para nosotros trabajando con la interfaz no nos importa si lo que hay detrás es una bicicleta o un coche. Un caso claro es cuando recibimos esa interfaz en un método.

void AvanzarHacia(IVehiculo vehiculo, int grados)
{
    vehiculo.Girar(grados);
    vehiculo.Avanzar();
}

Hasta aquí no te estoy contando nada nuevo, esto son las interfaces de siempre.

¿Por qué han cambiado las interfaces en C#8?

Hasta ahora una interfaz que ya se había distribuido y se estaba utilizando era inmutable. En el ejemplo del código anterior, si la estamos utilizando y dentro de un tiempo nos damos cuenta de que hay que añadir un nuevo método y lo añadimos, vamos a romper la compilación. Esto es porque precisamente la interfaz nos obliga a implementar todos sus métodos.

¿Imaginas que pasaría si el equipo de desarrollo de Microsoft se diese cuenta de que IDisposable necesita añadirle más métodos?

La respuesta es muy simple: Romperían todo el ecosistema. Todos los proyectos que tengan alguna clase que implementase IDisposable dejarían de compilar al instante hasta que se añadiese ese método extra de la interfaz. Si echamos un ojo al código de .Net o .Net Core podemos comprobar que son miles las clases que implementan IDisposable. Eso solo dentro del propio framework, si hablamos de su uso por parte de los desarrolladores en librerías y productos, el número de clases que se romperían es tan grande que no podemos ni imaginarlo.

Por supuesto un cambio así que es un breaking change en toda la expresión del término no se puede aplicar sin hacer un cambio de versión «major». Hacerlo sin actualizar la versión sería el final del lenguaje, pero aun actualizando la versión… ¿Estarías dispuesto a rehacer todo el código de un proyecto solo para actualizarlo de versión? ¿Y si no ha cambiado solo IDisposable? Desde luego la acogida de esa nueva versión sería mucho más complicada. Aquí es donde entran los cambios que nos trae C#8. Pero…

¿En que han cambiado las interfaces con C#8?

Precisamente la novedad que tenemos con respecto a las interfaces es que ahora si pueden tener una implementación por defecto. Espera…

WHAT???!! ¿Si una interfaz tiene una implementación por defecto no es una clase abstracta?

Sí. Con anterioridad a C#8 si queríamos tener una implantación por defecto elegíamos una clase abstracta y sino una interfaz. La separación estaba clara. Esto ahora ha cambiado y si por ejemplo después del tiempo nos diésemos cuenta de que la interfaz del ejemplo que hemos puesto no es útil porque en vez de especificar los grados queremos solo decirle también que gire a izquierda y derecha podríamos hacer una interfaz así:

public interface IVehiculo
{
    void Avanzar();
    void Girar(int grados);
    void GirarDerecha() => Girar(90); //Implementación por defecto
    void GirarIzquierda() => Girar(-90); //Implementación por defecto
}

El hecho de actualizar esta interfaz no va a provocar un error de compilación ya que si no encuentra una implementación en la clase para ese método va a utilizar la implementación por defecto.

Este cambio en las interfaces de C#8 no viene solo. Hasta ahora todos los métodos de una interfaz pública eran públicos y esto tenía todo el sentido. Si se definían unos métodos que la clase tenía que implementar, lógicamente tenían que ser accesibles. Como ahora ya no es obligatorio que esos métodos estén todos implementados.

Nuevos modificadores de las interfaces en C#8

Precisamente de lo que hemos visto anteriormente el siguiente paso natural es que una interfaz no sea completamente pública, puede que necesitemos cierta lógica no pública para poder manejar esos casos por defecto. Es por eso que ahora los modificadores de disponibles son:

Con ellos vamos a poder aplicar la lógica necesaria para poder generar funcionamiento por defecto para las interfaces. Puedes ver un ejemplo en que ofrece el equipo de dotnet directamente en github.

¿Cómo se comporta este funcionamiento por defecto?

En primer lugar, toda la implementación está en la propia interfaz y no en la clase que la implementa. Estas implementaciones por defecto no son un tipo de herencia múltiple encubierta. Es decir, si la interfaz tiene una implementación por defecto de un método que la clase no tiene, solo será accesible desde la interfaz y no desde la clase. De hecho, no es una multiherencia ni si quiera a nivel de interfaz, si por ejemplo heredamos nuestra interfaz de dos o más que si tienen el mismo método por defecto, vamos a necesitar especificar cual exactamente queremos utilizar o se generará un error de ambigüedad. Por ejemplo:

public interface IVehiculoTerrestre
{
    void Avanzar() => Console.WriteLine("Avanzar por tierra");
}

public interface IVehiculoNaval
{
    void Avanzar() => Console.WriteLine("Avanzar por mar");
}

public interface IVehiculoHibrido : IVehiculoTerrestre, IVehiculoNaval
{
}

public class VehiculoHibrido : IVehiculoHibrido
{
}


IVehiculoHibrido vehiculo = new VehiculoHibrido();

vehiculo.Avanzar(); //Error de ambigüedad. No compila
((IVehiculoTerrestre)vehiculo).Avanzar(); //Avanzar por tierra
((IVehiculoNaval)vehiculo).Avanzar(); //Avanzar por mar

Y… ¿Dónde está el problema entonces?

De lo que hemos visto más arriba podemos sacar en claro que, aunque es una utilidad interesante y que va a permitir actualizar las interfaces sin miedo a romper un montón de código. El problema viene de que la línea que he separado históricamente las interfaces y las clases abstractas se ha difuminado tanto que se ha convertido en buenas prácticas que en una separación real de funciones. Precisamente por eso muchos opinan que es una característica que dificulta el lenguaje y lo hace confuso porque el lenguaje ya tenía una manera de resolver eso antes de las interfaces de C#8, las clases abstractas. Si alguien quería proveer una implementación por defecto era una clase abstracta lo que debía usar.

Otra de las razones de los detractores de este cambio es que al haber una implementación por defecto ya no hay errores de compilación si la interfaz que estas implementando en tu clase tiene métodos no implementados en la propia clase. Esto puede llevar a errores difíciles de detectar cuando trabajas con la abstracción que te da una interfaz… Imagina que tu método recibe una interfaz y cuando llamas a su método ‘x’ actúa una implementación por defecto sin que tú te estés dando cuenta… Dependiendo de la situación esto puede ser un gran problema.

Personalmente pienso que una característica como las interfaces de C#8 no es ni buena ni mala por si sola. Puede ser muy útil en determinados casos y provocar fallos muy graves en otros y es nuestra labor como desarrolladores conseguir que el mundo sea mejor.

La imagen muestra una escena de Spiderman donde el Tio Ben dice su famosa frase: "Un gran poder conlleva una gran responsabilidad"

¿Qué opinas tú de esta nueva característica? ¿Crees que mejora o que empeora el lenguaje? No dudes en dejar un comentario dando tu opinión sobre el tema.

**La entrada Novedades de C#8: Interfaces. ¿Qué podemos esperar? se publicó primero en Fixed Buffer.**

Coding Potions: Cómo usar el Vue router y ciclo de vida de los componentes

$
0
0

Introducción

Vue, como muchos otros frameworks para el desarrollo web (Angular, React) también tiene un sistema para crear rutas. Como hemos explicado en capítulos anteriores, Vue permite crear páginas web SPA, es decir, el usuario tiene la sensación de que está navegando entre las páginas pero lo que de verdad ocurre es que Vue por debajo está cambiando el HTML al vuelo sin tener que recargar la página.

Es decir, por ejemplo, si estás en la página principal de una aplicación SPA y navegas a la URL /users, Vue lo que hace es renderizar el componente asociado a esa ruta en la página web. Como ese componente ya lo tiene cargado el cambio entre páginas es inmediato.

Para conseguir esto, el creador del Vue router (que es español por cierto) ha desarrollado un conjunto de utilidades para crear rutas en Vue. Es decir, en un fichero configuras las rutas que quieres crear y las asocias a componentes que se cargarán cuando el usuario navegue a la ruta.

Cómo funciona el vue-router

Si has instalado Vue con el Vue CLI y has seleccionado el método manual, te habrá salido la opción de instalar el vue router. Si no lo tienes instalado no te preocupes porque vamos a ver cómo se instala.

Antes de nada, para saber si lo tienes instalado mira en el archivo package.json si tienes dentro de la sección dependencias un paquete llamado:

"vue-router":"^3.0.3"

En mi caso tengo la versión 3.0.3 pero tú puedes tener otra versión, no pasa nada.

Si no tienes instalado vue-router lo que tienes que hacer es instalarlo dentro del proyecto, para ello, mediante línea de comandos ejecuta:

npm install vue-router --save

A continuación, lo que tienes que hacer es crear un archivo llamado router.js dentro de la carpeta src, al mismo nivel que el main.js.

Dentro del archivo lo primero que tienes que hacer es importar Vue y vue-router y hacer que vue use el router, así:

importVuefrom"vue";importVueRouterfrom'vue-router'Vue.use(VueRouter)

Si el vue-router lo instalaste con vue-cli al crear el proyecto este archivo ya lo tendrás.

Las rutas se crean en un array con esta sintaxis:

constroutes=[{path:"/",name:"home",component:Home}];

En este caso hay una sola ruta, la ruta raíz, es decir, la que se abre al abrir la página.

Como ves cada ruta se crea en forma de objeto con propiedades. En el path indicas la ruta que quieres que se use (por ejemplo “/users”), en el name puedes darle un nombre a la ruta para identificarla posteriormente, y en el component pones el componente que quieres que se use en esa ruta, así que tendrás que importarlo de esta forma:

importHomefrom"./views/Home.vue";

Si te fijas las rutas las importo desde una carpeta llamada views dentro del src. Esto se hace para poder identificar bien qué componentes se encargan de cada una de las vistas. Es decir si quieres localizar el componente que se encarga de renderizar la ruta /users lo único que tienes que hacer es ir a carpeta views para buscar un componente llamado Users o parecido.

Debajo de las rutas, en el mismo fichero, tienes que meter esto para que Vue pueda usar las rutas que acabas de crear:

constrouter=newRouter({mode:"history",routes});exportdefaultrouter;

Se hace el export para que en el main.js podamos pasar las rutas a Vue, es decir, dentro del archivo main.js del src tienes que meter esto para que funcione:

importVuefrom"vue";importAppfrom"./App.vue";importrouterfrom"./router";newVue({router,render:h=>h(App)}).$mount("#app");

Y listo, con esto ya tendríamos una ruta funcionando en Vue. Si quieres añadir más rutas lo que tienes que hacer simplemente es añadir más objetos al array de rutas del archivo router.js que acabas de crear, así:

importVuefrom"vue";importVueRouterfrom'vue-router'importHomefrom"./views/Home.vue";importUsersfrom"./views/Users.vue";Vue.use(VueRouter)constroutes=[{path:"/",name:"home",component:Home},{path:"/users",name:"users",component:Users}];constrouter=newRouter({mode:"history",routes});exportdefaultrouter;

Cuando navegues a la ruta [http://localhost:8080/users](http://localhost:8080/users) se cargará el componente Users de la carpeta views y por tanto se verá lo que haya en ese componente. Al navegar a la ruta principal, es decir, a [http://localhost:8080/](http://localhost:8080/users) se cargará el componente Home.

Ciclo de vida de un componente en Vue

Visto cómo crear rutas en Vue, el siguiente paso en tu aprendizaje es comprender lo que ocurre cuando entras en la ruta, es decir, el controlar el ciclo de vida de los componentes.

Los componentes, en todos los frameworks, tienen ciclo de vida, en otras palabras, los componentes, se crean, se cargan, se insertan en ls vista y se destruyen, y lo bueno de esto es que puedes ejecutar código en cada uno de estos estados.

Aunque Vue tiene muchos métodos para distintos estados, voy a explicar los mas habituales, los que acabarás usando siempre, ya que el resto se usan mucho menos. En este gráfico puedes ver el ciclo que sigue Vue para los componentes.

Ciclo de vida de los componentes de Vue: Created, mounted, destroyed

Por cierto, una limitación que tienen estos estados es que no puedes usar dentro arrow functions, no puedes hacer esto porque se pierde el contexto del this y ya no puedes acceder al data y a los métodos.

Si quieres hacer algo de este estilo tienes que guardarte el valor del this o hacer un bindeo del mismo.

()=>this.fetchTodos()

Created

Uno de los que más se usan. Se ejecuta después de beforeCreated. En ese punto Vue ya ha cargado todas las opciones del componente y por tanto ya existe la sección data y los métodos. Aquí puedes hacer llamadas a variables y puedes ejecutar métodos.

La única pega es que en este punto Vue todavía no ha cargado la vista, no la ha renderizado y no puedes leer o modificar nada que afecte a ls vista porque todavía no existe. No puedes acceder al DOM de ese componente.

Este método se suele usar para realizar las llamadas API REST, por ejemplo si queremos pintar un array con información que provenga del backend lo que se suele hacer es dentro del created hacer la llamada y almacenar el valor de retorno de una de las variables del data. Como Vue es reactivo, cuando la vista esté cargada se pintará el array.

Veamos un ejemplo:

<script>exportdefault{data:()=>({info:null,}),created(){this.info="Componente cargado";}};</script>

Si te fijas lo que se hace es declarar un método created, usualmente debajo de los métodos al final del componente.

Como vimos en los métodos, para acceder a las variables se utiliza el this, en este caso para poner un valor a una variable. También podemos llamar a métodos de la sección methods con el this e incluso podemos hacer uso de las propiedades *computadas.*

Mounted

A diferencia del created, en el mounted si que tenemos acceso al DOM, es decir, el computed se ejecuta exactamente cuando se termina de pintar la vista en la página web y por tanto desde aquí podemos hacer cambios en la vista.

<template><ahref="/link">link</a></template><script>exportdefault{data:()=>({info:null,}),mounted(){console.log(this.$el.querySelectorAll('a'));}};</script>

Si te fijas, para acceder a un elemento del DOM se puede hacer mediante la variable que crea Vue al renderizar el componente this.$el.

Si te salta un error porque no existe el elemento, una forma de asegurarse de que Vue ya ha renderizado todos los elementos del DOM es usar la función nextTick de Vue.

<template><ahref="/link">link</a></template><script>exportdefault{data:()=>({info:null,}),mounted(){this.$nextTick(()=>{console.log(this.$el.querySelectorAll('a'));});}};</script>

La función nextTick lo que hace es dejar pasar un pequeño intervalo de tiempo, el correspondiente a un tick.

Updated

Con este método hay que tener mucho cuidado. Se ejecuta cada vez que se produce un cambio en el componente y cambia algo de la vista. Se recomienda aquí no hacer muchos cambios en el data o en la vista y utilizar propiedades computadas o watchers que veremos más adelante.

<script>exportdefault{data:()=>({info:null,}),updated(){console.log("Componente actualizado");}};</script>

Hay que tener cuidado porque puede que se ejecute más veces de las que en realidad queremos.

Destroyed

Como puedes suponer, el destroyed se ejecuta cuando eliminamos un componente, cuando ya no esta cargado. Esto puede pasar cuando cambias de vista o cuando o cuando se borra un componente del DOM porque ha sido ocultado con v-if.

<script>exportdefault{data:()=>({info:null,}),destroyed(){console.log("Componente eliminado");}};</script>

Conclusiones

Existen muchos más métodos en el ciclo de un componente de Vue como el beforeCreated o el beforeMounted, pero no he querido explicar más porque no quiero alargar demasiado el artículo. Además los que te he enseñado aquí son los que más va a usar y los otros en raras ocasiones te harán falta.

Hasta ahora ya hemos visto cómo se crean componentes, cómo crear rutas de la web y cómo controlar el ciclo de vida de los componentes, falta ver otra de las partes más importantes del desarrollo de aplicaciones wen con componentes y es la comunicación entre ellos, el paso de información. En posteriores capítulos abordaremos esta cuestión, no te lo pierdas.

Blog Bitix: Artículo #7 de Yo apoyo al software libre

$
0
0
Calibre

Continuando con la serie de artículos comentando las donaciones que voy realizando a los proyectos de software libre en este caso comentaré otro programa que uso habitualmente. En este caso de trata del programa el gestor gestor de libros electrónicos y conversor entre diferentes formatos de libro electrónicos Calibre que que quizá no tiene la interfaz de usuario más atractiva pero es muy útil, funciona realmente bien y permite tener organizada la biblioteca digital.

Lo uso habitualmente para convertir los libros en formato epub a mobi para poder leerlos en el lector de libros electrónicos Amazon Kindle. El programa Calibre es software libre y gratuito pero ofrece la opción de realizar una donación para contribuir al mantenimiento del proyecto que el desarrollador o desarrolladores seguro agradecen para costear sus gastos ayudándoles a realizar nuevas mejoras en el programa.

Hace unos meses se publicó la versión 4.0 del programa y cada semana o dos semanas hay una nueva versión que incluye correcciones y algunas mejoras, aún usando la distribución de GNU/Linux como Arch Linux siendo rolling release y actualizando el sistema cada dos semanas es uno de los pocos programas que habitualmente tengo desactualizado en una versión anterior a la última, eso es resultado de las numerosas versiones que se publican del mismo.

Bibliteca y conversor de libros electrónicos Calibre

La cantidad que he donado no es mucho pero si un porcentaje de los usuarios que lo utilizan realizarán una pequeña donación el proyecto continuará desarrollándose. Muchos programas de software libre utilizados por usuarios e incluso empresas que ganan millones de dólares confían en proyectos que en algunos casos solo están mantenidos por una persona y de forma voluntaria en su tiempo libre sin recibir un sueldo a cambio.

Una donación en la medida que uno pueda o desee es una buena forma de si un programa le es realmente útil devolver algo en compensación de su uso. A continuación el recibo de la donación que he realizado a Calibre.

Donación Calibre

Recuerda que si no es por privacidad y usas un bloqueador de anuncios desactivándolo en Blog Bitix ayudas a que pueda seguir haciendo estas donaciones aún siendo pequeñas y una parte pequeña de los ingresos que me genera el blog.

Donaciones que he realizado hasta la última fecha
# Fecha Proyecto Donación
12015/12Free Software Foundation Europe (FSFE)40€
22016/09Wikipedia, Firefox10€, 10€
32017/01elementaryOS, Libre Office, Arch Linux ARM10€, 10€, 10€
42017/05GNOME, VideoLAN (VLC), Arch Linux15,31€, 10€, 0,31€
52018/01LineageOS, Replicant15€, 15€
62018/12Wine$20
72019/12Calibre$10
Total145€, $30

Variable not found: Enlaces interesantes 385

$
0
0
Enlaces interesantes
Ahí 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

Xamarin

Publicado en Variable not found.

Variable not found: El "SantaGate" de Visual Studio Code ( y ¡felices fiestas!)

$
0
0
Feliz Navidad!En primer lugar, quería desearos a todos unas felices fiestas; como debe ser, espero que descanséis y aprovechéis para pasar estos días disfrutando de la familia y amigos. Y ya puestos, espero también que el 2020 sea un gran año para todos.

Pero al hilo de estas fiestas, por si alguno no estáis al tanto, me ha parecido interesante aprovechar la ocasión para contaros un curioso cuento de navidad: la que se ha liado hace unos días en el repositorio de Visual Studio Code en Github, algo que algunos ya han denominado el "SantaGate".

Por si no estáis al tanto, resulta que en una reciente actualización para insiders de Visual Studio Code, alguien pensó que sería una buena idea añadir al IDE algunos detalles navideños para desear a la comunidad unas felices fiestas. Uno de ellos era un simpático gorrito de Santa Claus sobre el icono de configuración:

Gorro de Santa Claus en Visual Studio Code para Insiders

Lo que en principio podía considerarse como un acto inocente, fue criticado duramente horas más tarde a través de un issue del repositorio, titulado "Santa Hat on vscode insiders and pushing of religion is very offensive to me":

Protesta contra el icono del gorro

Más o menos, la traducción del texto principal es algo como:
"El gorro de Papá Noel en VSCode para insiders, y la promoción de la religión me resulta muy ofensivo. Además, la Navidad ha costado la vida a millones de judíos a lo largo de los siglos, pero incluso si ese no fuera el caso, promocionar símbolos religiosos como parte de una actualización del producto es completamente inaceptable. Conviertan este asunto en su máxima prioridad y elimínenlo de inmediato. Para mí esto es casi igual de ofensivo que una esvástica."
Como explican desde el equipo del proyecto en esta entrada, también en GitHub, a la lectura de este issue y con el fin de no herir sensibilidades, decidieron retirar el gorro y añadir un copo de nieve. Sin embargo, a muchos usuarios tampoco les gustó el cambio, iniciándose una gran oleada de comentarios e issues: algunos jocosos, otros ofensivos, algunos creados por usuarios reales, pero otros por usuarios temporales o incluso por bots, que saturaron el repositorio.

Algunos ejemplos:
Pero la cuestión es que el repositorio comenzó a llenarse de contenidos que no tenía relación directa con Visual Studio Code, por lo que decidieron bloquearlo para hacer limpieza y esperar a que la cosa se calmara un poco. Durante 24 horas no se pudieron introducir nuevos comentarios ni issues, se eliminaron contenidos ofensivos y se marcaron como off-topic y cerraron aquellos que, sin ser ofensivos, no tenían estrictamente que ver con el proyecto.

¿Y cuál ha sido la solución final respecto al gorro de Santa Claus? Pues hacer que esta opción sea configurable: han habilitado un setting en VS Code para insiders que permite personalizar el icono a mostrar. Así, todo el mundo contento :)

¡¡Felices fiestas!!

Publicado con espíritu navideño en Variable not found.

Fixed Buffer: Feliz Navidad 2019

$
0
0
La imagen muestra unos arboles de navidad con nieve

Llegan las navidades y es momento de estar con los tuyos y descansar. Quizás comer y beber de más, cantar algún que otro villancico, reír, bailar…

Son las segundas navidades de FixedBuffer y no podría estar más contento de que este proyecto salga adelante. Como esto no es una entrada sobre temas técnicos tampoco me quiero enrollar (que ya bastante lo hago durante el año…)

¡¡Felices fiestas y próspero año 2020!! Os deseo la mejor de las suertes y que disfrutéis de unas vacaciones tranquilas. Dentro de poco volveremos a dar guerra con muchos e interesantes temas.

¡¡Muchas gracias a todos por hacer que este proyecto siga adelante!!

P.D: Como el gran José Aguilar de Variable Not Found se me ha adelantado escribiendo sobre ello, os dejo una felicitación navideña con un suceso muy gracioso e interesante (recomendada lectura 100%).

**La entrada Feliz Navidad 2019 se publicó primero en Fixed Buffer.**

Variable not found: Ostrich Design Pattern, y su soporte en C# 9

$
0
0
Un reciente estudio de la consultora Garner indica que durante el desarrollo de una aplicación dedicamos más del 80% de nuestro tiempo a implementar controles de posibles fallos.

Además, este otro informe de StackOverflow obtenido tras analizar el código fuente de miles de proyectos open source, el control y tratamiento de excepciones y problemas supone más del 60% de nuestra base de código y, por tanto, aporta gran parte de la complejidad interna de las aplicaciones.

Pero, adicionalmente, estos estudios ponen al descubierto otros tres aspectos bastante interesantes:
  • Primero, que la mayoría de errores que intentamos controlar no se van a producir nunca. Son posibles a nivel de flujo de código, pero en la operativa de la aplicación no ocurrirán, por lo que podríamos decir que son problemas creados artificialmente durante el proceso de desarrollo.
     
  • Segundo, las líneas de control de errores no están exentas de problemas, por lo que muy a menudo encontraremos en ellas nuevo código de control (¿quién no ha visto try/catch anidados a varios niveles?), por lo que la bola de nieve no para nunca de crecer: código de tratamiento de errores que a su vez contiene código de tratamiento de errores, y así hasta el infinito.
     
  • Y por último, también nos encontramos con que en muchas ocasiones el código de control no hace nada. Por ejemplo, se cuentan por millones las líneas de código detectadas en Github cuyo tratamiento de excepciones consiste simplemente en la aplicación a rajatabla del Swallow Design Pattern, por ejemplo, implementando bloques catch() vacíos.
Y conociendo estos datos, ¿por qué dedicamos tanto tiempo a la gestión de errores en nuestro código? Pues básicamente porque hemos sido educados para eso. Exceptuando cuando se nos cala el coche, no hay nada que suponga un golpe al ego tan importante como cuando una de nuestras aplicaciones falla, y por eso no escatimamos recursos a la hora de evitarlo.

¿No estaría bien poder ignorar esos problemas y centrar nuestro código en aportar valor a nuestros clientes?

Introducing GoF's Ostrich Design Pattern (ODP)

Design Patterns BookSi, como el que os habla, sois unos seguidores incondicionales del Gang of Four y sus 23 patrones de diseño sabréis que el número 18 es el denominado Ostrich Pattern. Se trata de un patrón de diseño que describe una fórmula para el tratamiento de errores bastante más productiva y eficiente que la que solemos utilizar.

Básicamente, su enunciado es:
Para aumentar la productividad y evitar que los errores provoquen problemas de estabilidad y funcionamiento, lo más recomendable es ignorarlos.
O en otras palabras, ignorar los errores y no hacer nada con ellos es mejor tanto desde el punto de vista de la productividad como de la fiabilidad de las aplicaciones, pues:
  • No tendremos que perder tiempo en introducir código de control de errores.
  • La complejidad extra que debemos añadir a una aplicación para gestionar todos los posibles errores introduce un riesgo de fallo superior al que estamos intentando combatir.
  • Y, además, dado que la mayoría de estos errores no van a producirse nunca, el impacto de no controlarlos será prácticamente cero.
En la práctica, la aplicación de este patrón es bastante sencilla... y de hecho, llevamos décadas haciéndolo.

Los que trabajásteis con aquella maravilla prehistórica llamada QuickBasic, con las primeras versiones de Visual Basic (¡sí, cuando aún no llevaba el apellido .NET!), con su hermano pequeño VBScript, con VBA (Visual Basic for Applications) o incluso con Visual Basic .NET, seguro disfrutasteis de la seguridad y tranquilidad de introducir una sentencia como la siguiente:
On Error Resume Next
' Hacer algo que puede que falle
La sentencia On Error Resume Next es la implementación más conocida del patrón de diseño Ostrich.
On Error Resume Next simplemente indicaba al runtime que si se producía un error o excepción debía ignorarla y seguir ejecutando la siguiente instrucción. El siguiente ejemplo ilustra la diferencia entre usarlo o no hacerlo:
Sub Main(args As String())
Ostrich()
Classic()
End Sub

Sub Ostrich()
On Error Resume Next
DoSomethingWrong()
Console.WriteLine("This message will be shown")
End Sub

Sub Classic()
DoSomethingWrong()
Console.WriteLine("This message will never be shown")
End Sub

Private Sub DoSomethingWrong()
Throw New Exception("Boom!")
End Sub

Soporte ODP en C# 9

Seguro que estáis al tanto de que el equipo de diseño de C# está haciendo grandes esfuerzos por evitar los errores que más habitualmente encontramos en nuestras aplicaciones.

Prueba de ello es la reciente introducción de los tipos referencia anulables, que pueden ayudar a evitar en gran medida los recurrentes null reference exceptions. Sin embargo, ¿qué pasa con el resto de errores? Y aquí es donde entra el nuevo soporte Ostrich nativo en la próxima versión de C#.

Ha habido bastante discusión al respecto en Github, pero existe ya un cierto acuerdo en que la sintaxis estará alineada con tecnologías existentes con objeto de facilitar su adopción. Por tanto, salvo que se introduzca algún cambio de última hora, podremos activar este nuevo modo permisivo ante errores de la siguiente forma:
public static void Main()
{
on error resume next; // Ostrich mode on
DoSomethingWrong();
Console.WriteLine("This line will be shown");
var x = 10 / 0;
Console.WriteLine("This line will be shown")
}

private static DoSomethingWrong()
{
throw new Exception("Yay!");
}
Como ocurría en otros lenguajes, la simple activación de este modo hará que cualquier excepción sea ignorada y la ejecución continúe por la línea siguiente.
La nueva instrucción on error resume next podrá utilizarse en cualquier ámbito, siendo aplicable exclusivamente al mismo. En el ejemplo anterior, el patrón ODP sólo se aplicaría en el interior del método Main(), pero el siguiente código muestra cómo podría ser aplicado a una clase completa:
public class InvoiceServices
{
on error resume next; // Ostrich mode in this class
public void AddInvoice(Invoice invoice);
public void RemoveInvoice(int id);
...
}
También puede ser aplicado a nivel de namespace:
namespace MyApp.Services
{
on error resume next; // Applied to all classes in this namespace
public class InvoiceServices { ... }
}
O a nivel de proyecto, introduciendo la instrucción fuera de los espacios de nombre:
on error resume next; // Applied to the entire application
namespace MyApp.Services
{
...
}

Mecanismos adicionales para gestionar ODP en C#

Lo que hemos visto hasta el momento será lo que habitualmente utilicemos en nuestras aplicaciones. De hecho, se prevé que la mayoría de desarrolladores apliquen on error resume next a nivel global, tal y como ya se está haciendo internamente en el código fuente del propio framework .NET 5.

Sin embargo, aun estando activado el modo de ignoración de errores, puede resultarnos interesante conocer si se ha producido algún problema. Para ello se ha introducido en el runtimela variable global Err, que siempre contendrá el último error producido:
public void MyMethod()
{
on error resume next;
var j = 0;
var i = 10 / j;
if (Err is DivideByZeroException ex)
{
// Hacer algo
}
}
Aunque se estima que habrá pocas razones para hacerlo, si queremos desactivar el modo Ostrich podemos hacerlo mediante la instrucción On Error Goto 0, de la siguiente forma:
public void MyMethod()
{
on error resume next; // ODP on
var j = 0;
var i = 10 / j;
Console.WriteLine("This line will be shown");

on error goto 0; // ODP off
var k = i / j;
Console.WriteLine("This line won't be shown");
}
Seguro que pensaréis que esto del goto 0 es algo extraño, pero está así por retrocompatibilidad y razones históricas, pues era como se hacía tradicionalmente en VB. Personalmente, creo que habría sido más acertado utilizar algo más explícito como on error crash o on error boom, que eran las otras alternativas que fueron consideradas por el equipo de diseño de C#.

En fin, otra de esas pequeñas mejoras que seguirán haciendo de C# el mejor lenguaje de programación, y que podremos comenzar a utilizar a mitad de enero, cuando sean lanzados C# 9, Visual Studio 2020, .NET Core 5, Entity Framework Core 7, LittlePony 2.0 y la primera versión de Web Forms Core.

Publicado en: www.variablenotfound.com.

Blog Bitix: Hemeroteca #16

$
0
0
Hugo

Se acaba otro año y en este caso además la década, en el siguiente 2020 harán 10 años ya desde que empecé a escribir artículos técnicos principalmente sobre GNU/Linux y Java, algunos artículos de opinión y desempaquetados los productos que compro relacionados con la tecnología. Una década escribiendo uno o dos artículos semanales, no es fácil aguantar durante todo este tiempo y conservar la motivación y tener el tiempo que requieren cada uno de los artículos. Muchos surgen de ideas del trabajo que en muchos casos no puedo aplicar laboralmente, salvo alguna pequeña excepción, por implementarlos en Java por mi preferencia en el caso de los de programación y usar otras tecnologías laboralmente.

Este segundo semestre he escrito algunos artículos menos, 34, frente a los 48 del primer semestre y es que con la compra de una Play Station 4 estoy dedicando parte del tiempo que antes dedicaba al blog e investigar tecnología a jugar a algunos videojuegos, aún así esa cantidad de artículos sigue siendo al menos uno por semana que es mi cadencia mínima de publicación que deseo. En total en el 2019 he publicado 82 artículos para llegar a la cifra de 453 artículos en el tiempo de vida de Blog Bitix desde finales del 2013, son muchos más teniendo en cuenta para ser algo que dedico en mi tiempo libre y cada caracter de los artículos requiere teclearlo, corregir las faltas de ortografía, hacer que las frases estén bien construidas sintácticamente y sean fáciles de comprender, cada idea e imagen a recortar y capturar está colocada de forma artesanal y manual, lo único automatizado es generar la versión estática de la web que gracias a Hugo junto con GitHub Pages y algunos comandos de GNU/Linux me permite centrarme más en solo escribir el contenido.

Pero los artículos no es lo único que he hecho este 2019, he recibido algunas pull request e issues para Script de instalación de Arch Linux desatendido, automatizado y personalizable y el repositorio en GitHub tiene una buena cantidad de stars y forks, he continuado manteniendo la traducción al español de VLC, he enviado una actualización con las nuevas cadenas y corregidos algunos errores de la traducción al español para la reciente versión 6.1 de VirtualBox y tratado de mejorar la de KeePassXC, algunas mejoras internas para generar el blog, incluido rediseñarlo para que el contenido esté centrado, más grande horizontalmente y publicidad lateral sticky.

Listando los artículos que he escrito durante este semestre, en la categoría de artículos de desempaquetado he escrito sobre la Play Station 4.

Dos de opinión.

Una de las temáticas principales de este blog es GNU/Linux, dentro de ella de diversa temática desde programación hasta el entorno de escritorio.

La otra temática principal de mi blog es la programación con el lenguaje Java donde están la mayoría de los artículos que he escrito.

En cuanto a las cifras del blog en número de visitas se ha mantenido prácticamente igual al 2018 con ~500K páginas vistas, a pesar de la cifra anualizada no son más de 1.5K al día que no es mucho, hay mucho margen de mejora. Aunque siempre es un punto de motivación normalmente no pienso en escribir artículos que atraigan a más lectores sino antes en lo que me apetece escribir y publicar. Aún escribiendo artículos más avanzados uno de los artículos más visitados es a pesar de su sencillez y simplicidad 4 formas de hacer un bucle for en Java, he escrito artículos mucho más avanzados que hacer varias formas de hacer un bucle for pero parece que los artículos sencillos tienen un público más amplio que los artículos más avanzados.

He escrito lo que en cada momento lo que me ha apetecido, lógicamente no desdeñanado conseguir más visitas pero sin ser esta la principal motivación de escribir algo. Como cada año, para observar las métricas pasados varios, hago públicos los datos de visitas en Analytics, ingresos de AdSense y de afiliación de Amazon. Por si a alguien sin blog, con uno o por comparar le resultan interesantes y quiere hacerse una idea.

Evolución visitas e ingresos en 2019

En cuanto a ingresos algunos menos 410€ frente a 480€ del año anterior, aún así todos los meses de forma consistente los ingresos están alrededor de entre 20 y 30 euros que no está mal.

Métricas de AdSense

En los ingresos por enlaces de afiliado de Amazon ha habido algunos meses especialmente notables y me sorprende que un solo blog como este le proporcione a Amazon facturar esa cantidad de dinero.

Aparte de la publicidad de AdSense la monetización por afiliación es una gran estrategia para conseguir ventas en un negocio beneficioso para las tres partes el editor que obtiene una recompensa por la venta motivándole a seguir escribiendo artículos que los usuarios consideren buenos como para finalizar en una compra, el usuario que dependiendo del artículo obtiene información objetiva que le disipa las dudas como para realizar con mayores garantías de hacer una buena compra y el vendedor que aumenta su facturación y en caso de que no se produzca la venta coloca enlaces dando su página de comercio electrónico a conocer con los enlaces disponibles para una futura ocasión u otros usuarios.

Esto es todo, ¡buen 2020!

¡Buen 2020!
Fuente: klowner.com

Coding Potions: Cómo crear y usar los props en Vue JS

$
0
0

Introducción

Una de las ventajas de los web components es que se pueden parametrizar, es decir, puedes pasar cierta información a los componentes para que se puedan adaptar dependiendo de las necesidades.

En el primer artículo de Vue (Tutorial básico componentes) ya vimos que las etiquetas HTML no son más que web components ya que tienen vista, estilos y lógica. Sabes que cuando creas un input, por ejemplo, puedes decidir si lo quieres de tipo text o de tipo password.

<inputtype="text"/><inputtype="password"/>

Pues a esto Vue lo llama props. En otras palabras, los props sirven para pasar parámetros o información al propio web component para poder personalizarlo y ajustarlo dependiendo de las necesidades.

Imagina que quieres crear un componente para mostrar un calendario. En principio puedes crearlo para que siempre se vea y funcione igual, pero también puedes crearlo para que sean más personalizables. Por ejemplo, puedes crearlo con la idea de poder cambiar el número de filas y columnas que se van a mostrar.

De esta forma podrías hacer algo parecido a esto:

<calendarcolumns="3"rows="6"></calendar>

Vue va más allá y no solo deja pasar números y strings en los props, también deja pasar objetos, arrays y variables reactivas.

Qué son los props y cómo se crean

Los props dentro del componente en el que se declaran no son más que variables. Como pasa con las variables, los props también son reactivos, es decir, cuando desde fuera el valor del prop cambie, automáticamente se actualizará la vista y las propiedades computadas asociadas a ese prop.

Los props se pasan desde el componente padre al componente hijo

Si no sabes lo que es una propiedad computada, te recomiendo que mires antes de continuar este artículo sobre eso:

Variables computadas en Vue

Los props los tienes que declarar dentro de la sección props del componente. A diferencia de las variables que declaras dentro del data, aquí no tienes que hacer un return ni tienes que usar una sintaxis rara, directamente declaras el objeto y dentro cada uno de los props.

<script>
export default {
  props: {
    title: String
  }
};
</script>

Como ves, se declarara el nombre del prop y seguido se pone su tipo.

Los tipos que puedes declarar son:

  • String: Para cadenas de texto.
  • Number: Para números.
  • Boolean: Para booleanos true/false.
  • Array: Listas ya sea de tipos básicos como de objetos.
  • Object: Objetos de javascript.
  • Date: Tipo fecha de javascript.
  • Function: Funciones.
  • Symbol: Símbolos.

Cuando el valor que viene de fuera no coincida con el tipo declarado saltará un error en Vue.

Lo bueno de los props en Vue es que le puedes colocar un valor por defecto en caso de que desde fuera no se pase, para ello el prop lo tienes que crear en forma de Objeto.

<script>
export default {
  props: {
    columns: {
      type: Number,
      default: 4
    },
    rows: {
      type: Number,
      default: 3
    }
  }
};
</script>

En el ejemplo anterior si no pasas filas y no pasas columnas se pondrán su valor declarado a default, 4 y 3 en este ejemplo.

También puedes declarar que el prop tiene que ser obligatorio, es decir, desde fuera al usar el componente siempre tendrías que pasar un valor o de lo contrario salta error. Para declarar la obligatoriedad tienes que usar la sintaxis de objeto también y usar la propiedad required.

<script>
export default {
  props: {
    columns: {
      type: Number,
      required: true
    },
    rows: {
      type: Number,
      default: 3
    }
  }
};
</script>

El prop para las columnas es obligatorio y por tanto no hace falta poner valor por defecto, porque cuando uses este componente siempre vas a tener que declarar ese valor. El prop para las filas en este ejemplo no es obligatorio (si no pones required es como si estuviera a false) y por tanto no hace falta que lo pases siempre.

Por como está hecho Vue, si quieres poner que el valor por defecto de un prop de tipo array sea array vacío, o quieres que un prop de tipo objeto por defecto sea objeto vacío, tienes que hacer este truquito para la propiedad default.

<script>
export default {
  dates: {
    events: {
      type: Array,
      default: () => []
    },
    config: {
      type: Object,
      default: () => {}
    }
  }
};
</script>

Mi consejo es que siempre uses la sintaxis de objeto en los props para que todo esté mucho más claro y que siempre declares la propiedad default.

<script>
export default {
  props: {
    // Evita hacer esto
    text: String,

    // Trata de hacer esto
    size: {
      type: Number,
      default: 0
    }
  }
};
</script>

Cómo usar los props dentro del componente

Los props los tienes que considerar como una variable más del data, es decir, puedes acceder desde cualquier método o computada a los props con el this.

<script>
export default {
  props: {
    columns: {
      type: Number,
      default: 4
    },
    rows: {
      type: Number,
      default: 3
    }
  },
  computed: {
    totalCells() {
      return this.columns * this.rows;
    }
  }
};
</script>

Como es lógico, desde la vista también puedes acceder a los props, igual que con las variables del data:

<template>
  <div class="content">
    <p>Rows: {{rows}}, columns: {{columns}}</p>
  </div>
</template>
<script>
export default {
  props: {
    columns: {
      type: Number,
      default: 4
    },
    rows: {
      type: Number,
      default: 3
    }
  },
  computed: {
    totalMonths() {
      return this.columns * this.rows;
    }
  }
};
</script>

También puedes usar los props dentro de los métodos, incluso dentro de la propiedad created.

<script>
export default {
  props: {
    columns: {
      type: Number,
      default: 4
    },
    rows: {
      type: Number,
      default: 3
    }
  },
  created(){
    console.log("Columns: " + this.columns + " Rows: " + this.rows);
  }
};
</script>

Cómo pasar los props al componente

Para usar un componente con props tienes que importarlo como ya vimos, y en la etiqueta tienes que pasar los props como un atributo más del html, es decir:

<template>
  <div class="home">
    <calendar :rows="6" :columns="5"  />
  </div>
</template>

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

export default {
  components: {
    Calendar
  }
};
</script>

Como pasaba como las propiedades dinámicas que vimos con las vistas, por defecto pasas el valor como string. Para poder pasar números, booleanos, arrays, variables definidas en el data, etc tienes que poner dos puntos antes de la propiedad:

<calendar columns="3" rows="6"></calendar>
<!-- Dentro del componente se reciben los números como string
Por lo tanto dentro del componente no podrías hacer un v-for porque cuenta
como string -->

<calendar :columns="3" :rows="6"></calendar>
<!-- Dentro del componente se reciben los números como números de javascript -->

<calendar :dates="[1,2,4,6,7,9]" :inline="true"></calendar>
<calendar :dates="[1,2,4,6,7,9]" inline></calendar>
<!-- Si quieres pasar un boolean con valor true puedes quitar los puntos
y lo que hay entre comillas para abreviar. Ambas formas son correctas -->

Ejemplo pasando a los props variables definidas en el data:

<template>
  <div class="home">
    <calendar :rows="rows" :columns="columns"  />
  </div>
</template>

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

export default {
  components: {
    Calendar
  },
  data: () => ({
    rows: 6,
    columns: 3
  })
};
</script>

Ejemplo pasando propiedades computadas a los props:

<template>
  <div class="home">
    <calendar :text="text"  />
  </div>
</template>

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

export default {
  components: {
    Calendar
  },
  data: () => ({
    rows: 6,
    columns: 3
  }),
  computed: {
    text() {
      return "Columns: " + this.columns + " Rows: " + this.rows;
    }
  }
};
</script>

Cómo usar los props en el Vue Router

Otra de las cosas que tienes que saber respecto a los props en Vue es que también puedes pasar props al navegar hacia rutas, es decir, los props no solo sirven para para pasar información desde un componente padre a un componente hijo, también puedes pasar props a una ruta cualquiera siempre y cuando estén activados.

Para activar los props en las rutas tienes que poner a true un parámetro especial que tienen las rutas al en el array de rutas que creas al configurar las rutas. Veamos un ejemplo:

router.js

{path:"/users",name:"users",component:Usersprops:true}

Con eso ya le decimos al vue router que esa ruta puede recibir props desde fuera. Veamos cómo se pasan las rutas al navegar a ellas con vue router.

Si recuerdas en anteriores capítulos vimos como usar Vue router para navegar a rutas. Para pasar props tan solo tienes que pue pasar un objeto params con los props ya puestos con el valor que quieres por ejemplo.

this.$router.push({name:'users',params:{title:'test title'}})

En este caso dentro del componente Users hay definido un prop llamado title.

IMPORTANTE. Solo se pueden pasar props a rutas navegando mediante el nombre del componente name. Si decides navegar a una ruta usando su URL, no se podrán pasar props de esta forma.

Conclusiones

Con los props vas a poder hacer componentes genéricos como botones, encabezados, etc que te van a permitir personalizarlos y usarlos en las condiciones que necesites, por ese motivo son muy usados en las librerías de componentes.

En posteriores capítulos veremos el caso contrario, es decir, pasar información desde el componente hijo al componente padre (por ejemplo saber cuando se pulsa un botón en el componente hijo desde el componente padre).

Israel Perales: Feliz año nuevo 2020

$
0
0
Feliz año nuevo 2020

2019 Fue un gran año para mi, hice casi todas mis metas profesionales o personales, metí muchos cambios en mi vida y aunque por N motivos no pude disfrutarlas como quisiera, allí están.

En el blog no he publicado lo suficiente, los borradores existen, solo siento que puedo mejorar la redacción y tengo pensado hacer videos en lugar de solo escribir, tratar con una forma diferente de hacer las cosas para salir de mi zona de confort en esta parte.

También intenté de dedicarle tiempo a otras cosas, comencé a ir al gimnasio, igual fui 1 semana al crossfit y al final corriendo por las noches, lo máximo que pude correr fueron 10k, creo que es importante el ejericio, me ayudo mucho a resolver problemas y suavizar otros, la excusa perfecta para hacerme con un Smart Watch.

Para no hacer mas largo el post espero que tengan un prospero año nuevo.

Navegapolis: Estimaciones ágiles, métricas de productividad, #NoEstimates y otros animales.

$
0
0

pezLos equipos ágiles no quieren saber cuánto trabajo llevan invertido en una tarea, sino cuánto falta para terminarla, porque no que les interesa contabilizar horas, sino mantener un ritmo de avance hacia la meta.

Los equipos que no tienen dificultades para mantener el avance o que se apoyan en otros criterios para lograrlo —como el ritmo de entrega— y que tampoco necesitan sincronizar su producción con la de otros equipos, consideran que las estimaciones son una práctica innecesaria.

Por las diferencias entre la agilidad y la gestión tradicional, estas son tres actitudes cuestionables en relación con las métricas ágiles:

 


Blog Bitix: Mejorar el tiempo de carga de una página web usando lazy load

$
0
0

Las páginas grandes y con muchos recursos como imágenes e iframes implementar la carga vaga o lazy load obtienen un gran beneficio, necesitando realizar menos peticiones en la carga inicial, con menos tamaño y cargándose en menos tiempo. Los navegadores han añadido soporte para desde JavaScript proporciona este soporte.

Firfox
Chromium

El tiempo de carga de una página web es una métrica importante para una buena experiencia de usuario, es una métrica evaluada por PageSpeed y también de cara al posicionamiento en los buscadores o SEO ya que influye en la fórmula que usa Google para clasificar y posicionar las páginas en la página de resultados de búsqueda, un buen posicionamiento en los buscadores es importante porque significa más visitas a una web que en muchos casos es la mayor fuente de usuarios. Un tiempo de carga alto hace que los usuarios abandonen la página antes de que esté cargada completamente, influyendo en el porcentaje de rebote y el tiempo de visita que se puede medir con Google Analytics.

Una de las variables que influyen en el tiempo de carga es el número de peticiones y el tamaño de los recursos de esas peticiones que se hacen al servidor para descargar los elementos de la página completa, estos son imágenes, hojas de estilo, archivos de JavaScript, iframes, … Sin embargo, los navegadores cargan todos los elementos de una página incluso aquellos que están en la parte baja e inicialmente no se ven hasta que el usuario se desplaza hasta visualizarlos. Cargar elementos que no se visualizan es innecesario e ineficiente en el navegador pero también para el servidor que ha de atender a más peticiones.

Los artículos de mi blog como Desempaquetado de PlayStation 4 Slim de 1 TB o Desempaquetado Intel NUC8i5BEK (Bean Canyon), HyperX Impact (RAM) y Samsung 970 EVO NVMe (SSD), incluyen numerosas imágenes e iframes de vídeos de Youtube y publicidad de Amazon, en todas se carga los comentarios de Disqus y para compartir los artículos con ShareThis que están al final de la página y hasta que el usuario no ha leido el artículo son innecesarios. Disqus además en concreto para cargarse realiza numerosas peticiones adicionales. Estás páginas son de las más complejas por número de recursos y extensión del artículo que tengo en el blog por lo que he analizado una de ellas antes y después aplicando lazy loading para cargar inicialmente solo los elementos que se visualizan que son aquellos que están en la parte superior de la página.

Páginas representativas de Blog Bitix

Analizando el número de peticiones, tamaño y tiempo de carga en la página de la PlayStation realizaban 343 peticiones inicialmente, con un tamaño de descarga de 5 MiB en un tiempo de carga según Firefox de 15 segundos. Evaluando esta página con PageSpeed un aspecto importante que indica a mejora reducir el número de elementos descargados, además de reducir peticiones y tamaño de la página se descarguen inicialmente los elementos importantes y omitiendo recursos de JavaScript hace que el desempeño sea mejor. El resultado es un menor tiempo de carga.

Métricas de carga en PageSpeed antes
Métricas de carga en Firefox

La solución es cargar los elementos imágenes, iframes, vídeos y comentarios de Disqus cuando se vayan a visualizar al desplazarse el usuario hasta ellos. Esto reduce notablemente el número de peticiones realizadas inicialmente, el tamaño de descarga y el tiempo de carga. Una librería de JavaScript que permite realizar esta funcionalidad es Lozad, no tiene dependencias, es muy pequeña, es soprendentemente fácil de utilizar en relación con el beneficio que aporta. Aprovecha el soporte de la interfaz IntersectionObserver precisamente proporcionada por los navegadores para realizar la carga vaga o lazy load de forma eficiente.

Para las imágenes e iframes hay que añadir una clase a los elementos de HTML y cambiar el atributo src a data-src. Los comentarios de Disqus se cargan con un archivo de JavaScript por lo que hay que retrasar la carga hasta que el elemento HTML que los contiene se visualice y con una función de callback se inicia la inserción de su recurso de JavaScript utilizando jQuery para cargar insertar en la página dinámicamente recursos JavaScript.

Este es una plantilla que utilizo para generar de forma estática el contenido del blog con Hugo en el que las imágenes ilustrativas de los artículos usan el atributo data-src e incluyen la clase de CSS lozad, en el código fuente o utilizando la función Inspeccionar se comprueba el HTML resultado. El otro archivo parte del JavaScript de este blog que implementa la carga vaga de las imágenes, iframes y scritps de Disqus y ShareThis. Para el caso de insertar JavaScript dinámicamente se observa un elemento con una expresión de jQuery y mediante una función callback que Lozad invoca cuando su elemento se visualiza momento en que se realiza la acción de insertar el recurso de JavaScript.

1
2
3
4
5
6
7
8
<divclass="media">    <figure>    <ahref="{ $imagescaled1.RelPermalink }"title="{ .Params.title1 }"data-gallery="data-gallery"><imgdata-src="{ $imagescaledthumb1.RelPermalink }"width="{ $imagescaledthumb1.Width }"height="{ $imagescaledthumb1.Height }"layout="responsive"class="lozad"></a>    <ahref="{ $imagescaled2.RelPermalink }"title="{ .Params.title2 }"data-gallery="data-gallery"><imgdata-src="{ $imagescaledthumb2.RelPermalink }"width="{ $imagescaledthumb2.Width }"height="{ $imagescaledthumb2.Height }"layout="responsive"class="lozad"></a>    <ahref="{ $imagescaled3.RelPermalink }"title="{ .Params.title3 }"data-gallery="data-gallery"><imgdata-src="{ $imagescaledthumb3.RelPermalink }"width="{ $imagescaledthumb3.Width }"height="{ $imagescaledthumb3.Height }"layout="responsive"class="lozad"></a>    <figcaption>{ .Params.caption }{ if .Params.source }<br/><small>{ i18n "source" }: { .Params.source }</small>{ end }</figcaption>    </figure></div>
figureproc.html
 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
require(['jquery','lozad','jquery-blueimp-gallery'],function($,lozad,blueimp){    ...    functioninitLazyload(){        varobserver=lozad('.lozad',{            rootMargin:'50px 0px'        });        vardisqusObserver=lozad('#disqus_thread',{            rootMargin:'50px 0px',            load:function(el){                $.ajax({                    url:'//'+disqus_shortname+'.disqus.com/'+disqus_script,                    async:true,                    cache:true,                    dataType:'script',                    success:function(){}                });            }        });        varshareThisObserver=lozad('div.sharethis-inline-share-buttons',{            rootMargin:'50px 0px',            load:function(el){                $.ajax({                    url:'//platform-api.sharethis.com/js/sharethis.js#property=5920c4ce1bd0670011e06acd&product=inline-share-buttons',                    async:true,                    cache:true,                    dataType:'script',                    success:function(){}                });            }        });        observer.observe();        disqusObserver.observe();        shareThisObserver.observe();    }    
    ...    initLazyload();});
main.js

Con simplemente esta mejora, que no es complicada de realizar, añadiendo el código anterior y realizando los sencillos cambios en los atributos de imágenes e iframes las métricas en la comparación con página anterior mejoran notablemente pasando apróximadamente de 15 segungos a menos de 4 en un tiempo de carga hasta que el navegador dejan de hacer peticiones.

PáginaMétricaAntesDespués
PlayStationFirefox343 peticiones, 5 MiB, 15s104 peticiones, 1.5 MiB, 3.5s
PlayStationPageSpeed2344
Intel NUCPageSpeed938

La métrica de PageSpeed mejoran notablemente, es una cifra sobre 100 que aún dista de ser alta debido a que Analytics y AdSense imponen una fuerte penalización por utilizarlos e incluirlos en las páginas. La página WebPageTest proporciona algunos datos adicionales y complementarios a los proporcinados por PageSpeed, también es recomendable usarla para medir la variación en los resultados con los cambios realizados con el objetivo de mejorar una página.

Métricas de carga en PageSpeed después
Métricas de carga en Firefox

Los navegadores van a añadir el soporte de carga vaga directamente en las imágenes e iframes con un el atributo loading mediante el cual el JavaScript anterior será innecesario para estos elementos.

En definitiva es un pequeño cambio sencillo de realizar y que mejora notablemente la experiencia de usuario, la carga del servidor, es recomendable para el SEO incluso desde el punto de vista de la privacidad de los usuarios.

Otro uso distinto para la carga vaga es lanzar eventos de Analytics, esto lo he empleado para saber si los usuarios llegan al final de los artículos. Con esto es posible obtener datos interesantes sobre cuales son las mejoras páginas o artículos, por ejemplo, para diferencia entre página muy visitada por que esté bien posicionada pero ni interesante para los uauarios porque no llegan al final del artículo o por el contrario páginas con pocas visitas pero que los usuarios las leen hasta el final.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
require(['jquery','lozad'],function($,lozad){    functioninitAnalytics(){        ...        varpageBottomObserver=lozad('#pageBottom',{            rootMargin:'50px 0px',            load:function(el){                ga('send','event','page','show','bottom',{'nonInteraction':1});            }        });        pageBottomObserver.observe();    }    ...    initAnalytics();    ...});
app.js

Blog Bitix: Mejorar el tiempo de carga de una página web usando lazy load

$
0
0

Las páginas grandes y con muchos recursos como imágenes e iframes implementar la carga vaga o lazy load obtienen un gran beneficio, necesitando realizar menos peticiones en la carga inicial, con menos tamaño y cargándose en menos tiempo. Los navegadores han añadido soporte para desde JavaScript proporciona este soporte.

Firefox
Chromium

El tiempo de carga de una página web es una métrica importante para una buena experiencia de usuario, es una métrica evaluada por PageSpeed y también de cara al posicionamiento en los buscadores o SEO ya que influye en la fórmula que usa Google para clasificar y posicionar las páginas en la página de resultados de búsqueda, un buen posicionamiento en los buscadores es importante porque significa más visitas a una web que en muchos casos es la mayor fuente de usuarios. Un tiempo de carga alto hace que los usuarios abandonen la página antes de que esté cargada completamente, influyendo en el porcentaje de rebote y el tiempo de visita que se puede medir con Google Analytics.

Una de las variables que influyen en el tiempo de carga es el número de peticiones y el tamaño de los recursos de esas peticiones que se hacen al servidor para descargar los elementos de la página completa, estos son imágenes, hojas de estilo, archivos de JavaScript, iframes, … Sin embargo, los navegadores cargan todos los elementos de una página incluso aquellos que están en la parte baja e inicialmente no se ven hasta que el usuario se desplaza hasta visualizarlos. Cargar elementos que no se visualizan es innecesario e ineficiente en el navegador pero también para el servidor que ha de atender a más peticiones.

Los artículos de mi blog como Desempaquetado de PlayStation 4 Slim de 1 TB o Desempaquetado Intel NUC8i5BEK (Bean Canyon), HyperX Impact (RAM) y Samsung 970 EVO NVMe (SSD), incluyen numerosas imágenes e iframes de vídeos de Youtube y publicidad de Amazon, en todas se carga los comentarios de Disqus y para compartir los artículos con ShareThis que están al final de la página y hasta que el usuario no ha leido el artículo son innecesarios. Disqus además en concreto para cargarse realiza numerosas peticiones adicionales. Estás páginas son de las más complejas por número de recursos y extensión del artículo que tengo en el blog por lo que he analizado una de ellas antes y después aplicando lazy loading para cargar inicialmente solo los elementos que se visualizan que son aquellos que están en la parte superior de la página.

Página PlayStationPágina PlayStation
Página Intel NUCPágina Intel NUC Páginas representativas de Blog Bitix

Analizando el número de peticiones, tamaño y tiempo de carga en la página de la PlayStation realizaban 343 peticiones inicialmente, con un tamaño de descarga de 5 MiB en un tiempo de carga según Firefox de 15 segundos. Evaluando esta página con PageSpeed un aspecto importante que indica a mejora reducir el número de elementos descargados, además de reducir peticiones y tamaño de la página se descarguen inicialmente los elementos importantes y omitiendo recursos de JavaScript hace que el desempeño sea mejor. El resultado es un menor tiempo de carga.

Métricas de carga en PageSpeed página PlayStation antesMétricas de carga de PageSpeed página Intel NUC antes Métricas de carga en PageSpeed antes
Métricas de carga de Firefox página PlayStation antes Métricas de carga en Firefox

La solución es cargar los elementos imágenes, iframes, vídeos y comentarios de Disqus cuando se vayan a visualizar al desplazarse el usuario hasta ellos. Esto reduce notablemente el número de peticiones realizadas inicialmente, el tamaño de descarga y el tiempo de carga. Una librería de JavaScript que permite realizar esta funcionalidad es Lozad, no tiene dependencias, es muy pequeña, es soprendentemente fácil de utilizar en relación con el beneficio que aporta. Aprovecha el soporte de la interfaz IntersectionObserver precisamente proporcionada por los navegadores para realizar la carga vaga o lazy load de forma eficiente.

Para las imágenes e iframes hay que añadir una clase a los elementos de HTML y cambiar el atributo src a data-src. Los comentarios de Disqus se cargan con un archivo de JavaScript por lo que hay que retrasar la carga hasta que el elemento HTML que los contiene se visualice y con una función de callback se inicia la inserción de su recurso de JavaScript utilizando jQuery para cargar insertar en la página dinámicamente recursos JavaScript.

Este es una plantilla que utilizo para generar de forma estática el contenido del blog con Hugo en el que las imágenes ilustrativas de los artículos usan el atributo data-src e incluyen la clase de CSS lozad, en el código fuente o utilizando la función Inspeccionar se comprueba el HTML resultado. El otro archivo parte del JavaScript de este blog que implementa la carga vaga de las imágenes, iframes y scritps de Disqus y ShareThis. Para el caso de insertar JavaScript dinámicamente se observa un elemento con una expresión de jQuery y mediante una función callback que Lozad invoca cuando su elemento se visualiza momento en que se realiza la acción de insertar el recurso de JavaScript.

1
2
3
4
5
6
7
8
<divclass="media">    <figure>    <ahref="{ $imagescaled1.RelPermalink }"title="{ .Params.title1 }"data-gallery="data-gallery"><imgdata-src="{ $imagescaledthumb1.RelPermalink }"width="{ $imagescaledthumb1.Width }"height="{ $imagescaledthumb1.Height }"layout="responsive"class="lozad"></a>    <ahref="{ $imagescaled2.RelPermalink }"title="{ .Params.title2 }"data-gallery="data-gallery"><imgdata-src="{ $imagescaledthumb2.RelPermalink }"width="{ $imagescaledthumb2.Width }"height="{ $imagescaledthumb2.Height }"layout="responsive"class="lozad"></a>    <ahref="{ $imagescaled3.RelPermalink }"title="{ .Params.title3 }"data-gallery="data-gallery"><imgdata-src="{ $imagescaledthumb3.RelPermalink }"width="{ $imagescaledthumb3.Width }"height="{ $imagescaledthumb3.Height }"layout="responsive"class="lozad"></a>    <figcaption>{ .Params.caption }{ if .Params.source }<br/><small>{ i18n "source" }: { .Params.source }</small>{ end }</figcaption>    </figure></div>
figureproc.html
 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
require(['jquery','lozad','jquery-blueimp-gallery'],function($,lozad,blueimp){    ...    functioninitLazyload(){        varobserver=lozad('.lozad',{            rootMargin:'50px 0px'        });        vardisqusObserver=lozad('#disqus_thread',{            rootMargin:'50px 0px',            load:function(el){                $.ajax({                    url:'//'+disqus_shortname+'.disqus.com/'+disqus_script,                    async:true,                    cache:true,                    dataType:'script',                    success:function(){}                });            }        });        varshareThisObserver=lozad('div.sharethis-inline-share-buttons',{            rootMargin:'50px 0px',            load:function(el){                $.ajax({                    url:'//platform-api.sharethis.com/js/sharethis.js#property=5920c4ce1bd0670011e06acd&product=inline-share-buttons',                    async:true,                    cache:true,                    dataType:'script',                    success:function(){}                });            }        });        observer.observe();        disqusObserver.observe();        shareThisObserver.observe();    }    
    ...    initLazyload();});
main.js

Con simplemente esta mejora, que no es complicada de realizar, añadiendo el código anterior y realizando los sencillos cambios en los atributos de imágenes e iframes las métricas en la comparación con página anterior mejoran notablemente pasando apróximadamente de 15 segungos a menos de 4 en un tiempo de carga hasta que el navegador dejan de hacer peticiones.

PáginaPruebaAntesDespués
PlayStationFirefox343 peticiones, 5 MiB, 15s104 peticiones, 1.5 MiB, 3.5s
PlayStationPageSpeed2344
Intel NUCPageSpeed938

La métrica de PageSpeed mejoran notablemente, es una cifra sobre 100 que aún dista de ser alta debido a que Analytics y AdSense imponen una fuerte penalización por utilizarlos e incluirlos en las páginas. La página WebPageTest proporciona algunos datos adicionales y complementarios a los proporcinados por PageSpeed, también es recomendable usarla para medir la variación en los resultados con los cambios realizados con el objetivo de mejorar una página.

Métricas de carga en PageSpeed página PlayStation despuésMétricas de carga de PageSpeed página Intel NUC después Métricas de carga en PageSpeed después
Métricas de carga de Firefox página PlayStation después Métricas de carga en Firefox

Los navegadores van a añadir el soporte de carga vaga directamente en las imágenes e iframes con un el atributo loading mediante el cual el JavaScript anterior será innecesario para estos elementos.

En definitiva es un pequeño cambio sencillo de realizar y que mejora notablemente la experiencia de usuario, la carga del servidor, es recomendable para el SEO incluso desde el punto de vista de la privacidad de los usuarios.

Otro uso distinto para la carga vaga es lanzar eventos de Analytics, esto lo he empleado para saber si los usuarios llegan al final de los artículos. Con esto es posible obtener datos interesantes sobre cuales son las mejoras páginas o artículos, por ejemplo, para diferencia entre página muy visitada por que esté bien posicionada pero ni interesante para los uauarios porque no llegan al final del artículo o por el contrario páginas con pocas visitas pero que los usuarios las leen hasta el final.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
require(['jquery','lozad'],function($,lozad){    functioninitAnalytics(){        ...        varpageBottomObserver=lozad('#pageBottom',{            rootMargin:'50px 0px',            load:function(el){                ga('send','event','page','show','bottom',{'nonInteraction':1});            }        });        pageBottomObserver.observe();    }    ...    initAnalytics();    ...});
app.js

Variable not found: Top ten 2019 en Variable not found

$
0
0
Lo más visto en 2019
Estrenamos este nuevo año y década (aunque esto último es bastante más discutible) siguiendo una de las grandes tradiciones de este blog: dedicar el primer post a repasar cuál fue el contenido publicado durante los doce meses anteriores que más os llamó la atención.

Pero antes, abusando de este pequeño slice de atención que me estáis prestando en este momento, quería aprovechar para desearos un 2020 repleto de salud y alegría, tanto en el plano personal como en el profesional.

Y ahora, al turrón...

Top ten 2019 en Variable not found

Comenzando por el final, y entrando en la lista del top ten casi igualado con otros artículos, encontramos el post donde presentaba EF6.TagWith. Se trata de un paquete NuGet inspirado en la característica de EF Core con el mismo nombre, que permite añadir etiquetas personalizadas a consultas realizadas desde Entity Framework. Una herramienta que espero que no os haga falta nunca ;)

Ya en novena posición empezamos a encontrar pistas de lo que ha sido la tendencia en 2019: el triunfo de los artículos destinados a explicar novedades del lenguaje C#, probablemente debido a las grandes novedades que se han presentado en su última versión. En este caso comenzamos con el nuevo operador de C#8 Null coalescing assigment "??=", una construcción imprescindible para simplificar la sintaxis de asignaciones a variables nulas.

Continuando en esta línea, en el puesto número ocho se encuentra el post Switch expressions en C# 8, describiendo también una de las nuevas sintaxis que vinieron de la mano de la última versión del lenguaje. En este caso, una fórmula para que determinados bloques switch sean más claros y concisos.

En el artículo Registro y obtención de múltiples implementaciones de servicios en ASP.NET Core, y un caso práctico que encontramos seguidamente vemos cómo aplicar principios SOLID y un patrón como Strategy para mejorar un escenario que podemos encontrar con cierta frecuencia.

En la sexta posición saltamos brevemente a Entity Framework Core. En el post Evaluación en cliente de EF Core: sus peligros y cómo evitarla veíamos cómo este framework gestionaba expresiones que no podían ser evaluadas en el servidor. Afortunadamente, con EF Core 3.0 han dado marcha atrás y ya no hay que tener en cuenta estas precauciones :)

Volvemos a C#, para estudiar una de las novedades principales de la versión 8, que llega con la promesa de evitar los fatídicos y frecuentes Null Reference Exceptions: Tipos referencia anulables en C# 8. Por fin, un freno para el "error del billón de dólares", aunque tendremos que adaptar las aplicaciones para que esto sea una realidad.

En cuarta posición de los posts más visitados encontramos un primer vistazo a otra de las perlas introducidas en C# 8 y, sin duda, la más controvertida: la implementación por defecto en interfaces. He de reconocer que a primera vista no me convenció mucho, pero conforme pasa el tiempo estoy empezando a verle la utilidad y casi les perdono que tengamos que reaprender eso de que "las interfaces son contratos" ;)

Ya en tercera posición, me he alegrado de encontrar una colaboración del amigo Jorge Turrado: Cómo crear un paquete NuGet y publicarlo en Nuget.org, un gran post que, sin duda, merecía estar en las primeras posiciones del ranking. Os recomiendo que no os perdáis su blog Fixed Buffer, porque encontraréis más, y de calidad.

And the winner is...El segundo puesto lo ocupa un artículo sobre una de las novedades más espectaculares que acompañaron a ASP.NET Core 2.2, a primeros del año pasado: El hosting in-process. Este modo de hospedado, que en las versiones más recientes es ya la opción por defecto, permitía cuadruplicar el rendimiento de nuestras aplicaciones for free, sin hacer apenas ningún cambio. Y doy fe de que el cambio es brutal en entornos que requieren gran velocidad de respuesta.

Y el premio para el artículo de 2019 más visitado recae en el magnífico post Antipatrones de asincronía en C#, un compendio de malas prácticas habituales a la hora de utilizar asincronía en nuestras aplicaciones. Hey, y puedo decir lo de "magnífico" sin rubor porque el mérito no es mío, pues solo hice de traductor autorizado del original C# Async Antipatterns de Mark Heath ;)

Por último, me gustaría añadir una mención especial a dos posts que publiqué hace sólo unos días, y por tanto no han tenido tiempo de recibir tantas visitas como otros menos recientes, pero aún así muestran posiciones destacadas en el top ten. Además, ambos parecen inocentadas, aunque sólo uno de ellos lo es:
Gorro de Santa ClausEl "SantaGate" de Visual Studio Code (y ¡felices fiestas!), una felicitación navideña acompañada de una disparatada curiosa historia que se ha vivido hace pocas semanas en el repositorio de Visual Studio Code en GitHub a cuenta del gorrito de Santa Claus. Sin duda, una prueba irrefutable de que hay gente pa tó 😉
Como de costumbre, aprovecho el 28 de diciembre para dar rienda suelta a la imaginación, y este año me he inventado un patrón de diseño: el Ostrich Design Pattern; si no lo conocéis, no dudéis en echarle un vistazo porque seguro que os será de mucha utilidad en vuestro día a día 😁
Y visto todo esto, ahora sí, ¡vamos a por 2020!

Publicado en Variable not found.

Picando Código: [Libro] Radicalized por Cory Doctorow

$
0
0

Cory Doctorow - RadicalizedEl primer libro que terminé de leer en 2020 fue Radicalized por uno de mis autores preferidos: Cory Doctorow. Este libro reafirma su lugar entre mis favoritos, ¡lo amé!. Es un poco diferente a las novelas que he leído: cuatro novelas cortas, distintas e independientes. Pero el formato no afecta para nada, lo recomiendo ampliamente.

Había leído muy poco al respecto para no enterarme mucho de la trama. Así cada cuento se me iba presentando medio sorpresa, aunque la tapa da algunas pistas de por dónde va la historia. “Cuatro cuentos de nuestro momento actual”, son tan humanos y reales que reflejan totalmente el estado de la sociedad en este momento en el tiempo. Por algo la contratapa del libro nos dice “Distopia is now”.

El primero es típico de Doctorow, una historia que no sabría si incluir el término “ciencia” en el género “ficción”. Al ser tan actual, pierde un poco lo especulativo característico de la ciencia ficción. El relato distópico que nos presentan podría haber pasado perfectamente en 2019. Esta tendencia se mantiene hasta el final, pero no se termina de perder del todo ese no sé qué de la ciencia ficción.

El autor tiene la costumbre y facilidad de practicar activismo mientras nos divierte con la historia. Explica problemas como el DRM (Gestión Digital de Restricciones), cómo funciona y por qué es una mala idea que exista. Cuenta con la capacidad de explicar temas técnicos de manera bastante sencilla. Temas familiares para quienes tenemos conocimientos informáticos, por lo que apela a nuestro nerdismo. Pero alienta también a aprender e interesarse más, y con suerte logra convertir a quien lee en activista a la vez.

El hilo conductor de la historia es una tostadora que no permite tostar cierto tipo de pan, y de ahí se desenlaza toda una trama que gira entorno a eso. Algo sumamente real y que lamentablemente puede pasar con cualquier dispositivo actual, sobretodo los que se conectan de manera estúpidamente innecesaria a Internet…

Después de esa historia tan característica, una sobre el racismo y la brutalidad policial en el contexto de un mundo con superhéroes. El personaje principal va a resultarle familiar hasta a la persona más alejada de los cómics y cine superheróico. Si bien tiene un nombre distinto, no es más que el universo alternativo de uno de los héroes de capa más populares. Me encantan los cómics que mezclan esto de la política con super poderes, ¿hasta dónde deberían llegar y hasta dónde deberían dejar a los humanos “sin poderes” decidir por sí mismos? Algunas buenas historias de este estilo leí en The Authority: Revolution por Ed Brubaker, Avengers de Geoff Johns, y un poco también en Silver Surfer: Parable por Stan Lee y Moebius que es un librazo.

El cuento está genial, y al terminarlo me quedé con ganas de leer algún cómic de superhéroes escrito por Cory Doctorow (In Real Life está bastante bueno) y algo más de este estilo de narrativa donde se cuestiona por qué los super héroes no se encargan de todos los problemas de la sociedad…

La siguiente es una de esas historias que da un poco de miedo leer por la paranoia de entrar en una lista de algún gobierno. Algo similar a lo que me pasó con Little Brother, se trata de la radicalización de ciertas personas en situación desesperada. Sin contar mucho de qué va la trama, es una buena crítica a ciertos sistemas impuestos por el capitalismo que… bueno, hacen lo que hace el capitalismo, lucrar con el sufrimiento humano. Creo que es el que te deja más “al borde de la silla” por saber qué va a pasar después.

Para cerrar el libro, el cuento de un señor llamado Martin que pasa años construyendo su búnker para sobrevivir al colapso de la sociedad. Un aspecto interesante que describe es cómo saber cuándo entrar al búnker. Con las noticias actuales y la forma en que manipulan a la sociedad, cualquier evento puede ser “El Evento” que da la señal de que el mundo se terminó de ir a la mierda y es hora de ir a encerrarse en el búnker. Martin selecciona a un grupo de personas para acompañarlo y volver a salir una vez que el caos haya terminado y se tenga que salir a rearmar una sociedad. En un escenario apocalíptico cuyo alcance desconocemos (como debería ser en el caso que realmente ocurriera), y que imaginarán que puede tener desenlaces variados y dispares. Pero el final no decepciona.

El mensaje que nos deja el libro y que pienso empezar a citar seguido:

– “Éste no es el tipo de pelea que ganamos, es el tipo de pelea que peleamos”
Cory Doctorow

Libro sumamente recomendable. En mi pila de libros para leer se encuentra su novela Walkaway. Probablemente sea mi próximo libro al terminar el que estoy leyendo en éstos momentos. En Twitter ha comentado de dos trabajos a publicar en el futuro: “Stalkerware”, una historia en el universo de Little Brother (fuente) y “The Lost Cause” una novela sobre verdad, reconciliación y el cambio climático (fuente).  Ansío leer ambos trabajos una vez publicados. Los títulos posiblemente cambien, la novela Walkaway tenía el título “Utopia” originalmente. Si quieren saber más, pueden seguir al autor en Twitter donde comparte el progreso de su escritura bajo el hashtag #dailywords.

Blog Bitix: Tomar capturas de pantalla de páginas web desde la línea de comandos o desde la interfaz gráfica con Firefox

$
0
0

El navegador web Firefox tiene una opción con la que poder tomar una captura de pantalla de una página web desde la línea de comandos, que es útil como parte de un proceso automatizado. Firefox también permite tomar capturas de pantalla de una página web desde su interfaz gráfica o desde la consola web.

Firefox

ccccHttpClient

Como norma general las pruebas de una aplicación deben estar automatizadas con una herramienta de testing. ccccPara el código Java una herramienta de pruebas es JUnit y ccccpara una aplicación web es Geb. Sin embargo, algunas pruebas que no son de funcionalidad de la aplicación sino en una aplicación web por ejemplo de estilos y de visualización en la pantalla, que la página se muestre correctamente. Para estos casos no queda más que revisar, visualizar y comprobar la corrección visual de la misma, una posibilidad es entrar en la página manualmente mediante su dirección y realizar la comprobación.

Sin embargo, las acciones manuales hay que evitarlas en la medida de lo posible y que sean las menos posibles realizando su automatización ya que consumen muhco tiempo dedicable a tareas de valor. En este caso realizando la automatización se evita abrir el navegador, introducir la URL de la página o navegar hasta ella por cada URL a probar.

Aunque la revisión visual no esté automatizada y dependa de intervención humana al menos evitando las acciones manuales de introducir la URL o navegar hasta ella supone un ahorro de tiempo importante. La correcta visualización de una página puede consistir en revisar una captura de pantalla de la página y la automatización consiste en obtener esa captura de pantalla.

Esta automatización es interesante también ya que guardando los archivos de captura permiten tener un registro del estado de la visualización de una página a lo largo del tiempo y ver los cambios que se han ido realizando.

Captura de pantalla desde la linea de comandos con Firefox

Para obtener la captura de pantalla el navegador ccccFirefox permite desde la línea de comandos cargar una página a partir de su URL y obtener su captura de pantalla guardándola en un archivo jpg o png. Las capturas de pantalla también se pueden tomar en un servidor ccccGNU/ccccLinux sin interfaz gráfica con un comando habiendo instalado Firefox previamente para este propósito.

1
$ firefox -P headless -headless --screenshot duckduckgo.png https://duckduckgo.com/
firefox-screenshot.sh

El parámetro -P indica el perfil a usar y hay que crear uno para tomar capturas de pantalla al mismo tiempo que está abierto el perfil personal en una ventana gráfica del navegador. Hay varias formas de crear un nuevo perfil en Firefox. Desde la página de configuración about:profiles, con el gestor de perfiles o desde la línea de comandos.

Perfiles de usuario en FirefoxGestor de perfiles de Firefox

Perfiles de usuario y gestor de perfiles de Firefox
1
$ firefox -p
firefox-gestor-perfiles.sh
1
$ firefox -CreateProfile headless
firefox-createprofile.sh

Si hay necesidad de tomar varias capturas de pantalla de diferentes URLs de la aplicación o diferentes páginas web, con un script del intérprete de comandos ccccBash y dada una lista de URLs una por línea en un archivo se realiza el bucle. El parámetro screenshot contiene el nombre de la imagen en el que guardar la captura y a continuación la URL de la que tomar la captura, el parámetro –window-size especifica el ancho del navegador al tomar la captura, cambiar el ancho permite observar como se visualiza la página en diferentes resoluciones de ancho (1366, 1600, 1920, 2560, …).

1
2
3
4
5
google,https://www.google.es
duckduckgo,https://duckduckgo.com
ubuntu,https://www.ubuntu.com
redhat,https://www.redhat.com
archlinux,https://www.archlinux.org
links.txt
1
2
3
4
5
6
7
#!/usr/bin/env bash
cat links.txt |whileread -r LINE
doNAME=`echo$LINE| cut -d \, -f 1`URL=`echo$LINE| cut -d \, -f 2`
  firefox -P headless -headless --screenshot "$NAME.png"$URL --window-size=1920done
firefox-screenshot-links.sh

El resultado son las siguientes capturas de pantalla.

GoogleDuckDuckGoUbuntu

RedHatArch Linux

Capturas de pantalla realizadas con Firefox en modo headless

Con un gran número de páginas validar visualmente cada una de las páginas mediante una imagen aun con la automatización de tomar la captura consume una buena cantidad de tiempo, para reducir el número de capturas a validar el archivo puede limitarse a unas representativas de la aplicación o unas aleatorias de todo el conjunto, con los comandos sort -R y head -3 se toman las 3 primeras líneas aleatorias del archivo, el comando sort las ordena de forma aleatoria y el comando head toma el número de líneas indicado.

1
2
3
4
5
6
7
#!/usr/bin/env bash
cat links.txt | sort -R | head -3 |whileread -r LINE
doNAME=`echo$LINE| cut -d \, -f 1`URL=`echo$LINE| cut -d \, -f 2`
  firefox -P headless -headless --screenshot "$NAME.png"$URL --window-size=1920done
firefox-screenshot-links-random-firts.sh

Captura de pantalla desde Firefox

Firefox también permite tomar capturas de pantalla desde la interfaz gráfica, con el botón derecho y la opción del menú emergente Hacer una captura de pantalla de la pantalla completa o de la parte visible en ese momento o también desde el Inspector que se muestra con el botón derecho y la opción Inspeccionar elemento y habilitando la opción Hacer una captura de pantalla de la página completa y si se desea Captura de pantalla al portapapeles con las opciones de los ajustes.

Ajustes para mostrar botón de captura en las herramientas del inspector

Ajustes para mostrar botón de captura en las herramientas del inspector

La consola web de Firefox también permite tomar capturas de pantalla escribiendo el comando :screenshot.

Viewing all 2726 articles
Browse latest View live