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

Blog Bitix: El juego XCOM 2 y guía de estrategia

$
0
0

XCOM 2 es un juego de estrategia, con combates de acción por turnos, una parte de rol al permitir personalizar los soldados y elegir sus nuevas habilidades al subir de rango, también para las armas, y otra parte de gestión de los limitados recursos ambientado en una lucha contra una invasión alienígena a la tierra. Sin una guía el juego el nivel difícil del juego se convierte en tormento siendo muy difícil de terminar con éxito.

El juego XCOM 2 continuación del juego XCOM: Enemy Unknown para la PlayStation 3 ha sido uno de mis primeros juegos que he jugado en la PlayStation 4 que compré en el 2019. La temática basada en la invasión de la tierra de los alienígenas en un género de juego es uno de los que me atraen, con una parte de estrategia tanto a la hora de gestionar recursos así como en el los combates por turnos junto con otra parte de rol en la que los soldados van adquiriendo nuevas habilidades, armas y componentes para hacerlas más poderosas.

Fue publicado en el año 2016, desarrollado por Firaxis Games y publicado por 2K Games, disponible en Windows, macOS, Linux, Xbox One y Play Station 4. Tiene una expansión, XCOM 2 : War of the Choosen. El juego está completamente traducido al español tanto en los textos como las voces. Posee una música que proporciona un ambiente épico en las batallas.

En el modo de veterano ya es difícil, en las dificultades comandante y leyenda se convierte en un tormento, si no se tiene una mínima guía de estrategia en el combate, si no se realizan las investigaciones adecuadamente en un orden de importancia, también en la construcciones de salas, al final se llega a un punto que la partida está perdida los alienígenas acaban por desarrollar el proyecto AVATAR conquistando la tierra que hay que impedir y al final es necesario volver a empezar empleando una mejor estrategia desde el principio. El juego no ofrece un tutorial completo ni mucha información ni de qué ventajas aporta cada investigación y cuál es la más importante a realizar en cada momento, para los combates no se convierta en muy difíciles y tener posibilidades de acabar con éxito hay que seguir una guía.

Cada partida es distinta ya que el juego tiene cierta aleatoriedad en los eventos oscuros que ocurren, la ubicación diferente de la base en el mapa del mundo y los mapas de las misiones lo que de da al juego con los niveles de dificultad cierta rejugabilidad.

Pantalla inicialMenú

Pantalla inicial y menú

En un momento de oferta en la Play Station Store en formato digital está en por 13€ desde un precio original de 50€, un gran precio precio para un gran juego que ofrece una buena cantidad de horas de entretenimiento, más si una vez acabado el juego se optar por rejugarlo en un nivel más difícil. En Amazon está en formato físico. Al menos en la versión de la PlayStation 4 del juego en momentos concretos se producen tirones no se si por capacidad de la la PS4 o por un port deficiente en la consola, además los tiempos de carga y guardado incluso para mostrar los menús es significativo en parte puede ser debido a que la PS4 tiene disco duro mecánico y es común a todos los juegos de esta generación de consolas.

Esta es mi guía de estrategia del juego para que he seguido para acabar el juego. Algunos aspectos pueden variar según la preferencia o gusto de juego aunque en ciertas partes importantes será muy parecida.

Recursos

En ningún momento habrá recursos para todo, por lo que hay que priorizar en las cosas imprescindibles e importantes ni desperdiciarlos en cosas prescindibles. Incluso para no perder tiempo y tratar de desbaratar el proyecto AVATAR algunas misiones de recolección de recursos prescindibles que no apartan mucho beneficio han de dejarse de hacer, cada día que pasa en el calendario es un día menos para que los alienígenas completen su proyecto de dominación. En el cuartel general a cada inicio de mes existe la posibilidad de incorporar ingenieros o investigadores que en algunos casos también se obtienen en misiones.

Una vez contactado con el mercado negro este sirve tanto para vender botines sobrantes obtenidos en las misiones para obtener recursos en caso de necesidad, también para comprar mejoras de armas o SCP que sean útiles para añadir una propiedad de más movimiento, esquivar, vida o voluntad para resistir intentos de control de mente.

Ingenieros e investigadores

Los ingenieros permiten limpiar las salas del Avenger, realizar construcciones, dotar a las salas de equipos con algunas mejoras y realizar investigaciones de mejor armamento. Los ingenieros sobre todo y los investigadores son un recurso escaso por eso en el momento que aparezca una misión que tenga como recompensa un ingeniero o investigador conviene dar prioridad a estas sobre otras. Se pueden obtener en misiones o al inicio de cada mes en el cuartel general con lo que conviene incorporarlos si se tiene recursos necesarios.

Investigaciones

Es esencial y muy importante realizar las investigaciones prioritarias que permitirán obtener importantes mejoras en las armas para las misiones. En orden de prioridad conviene investigar las armas modulares que permite acoplarles miras telescópicas que proporcionan más puntería, mayor probabilidad de crítico o un mayor cargador y alguna de las armas magnéticas como fusil, rifle y escopeta que proporcionarán unas armas con mayor capacidad de daño, el cañón magnético para los granaderos no es tan importante ya su arma principal es el lanzagranadas, para ellos es más importante las ventajas que proporciona la autopsia del mutón con lanzagranadas avanzado y la granada de plasma.

En el apartado de armaduras los materiales híbridos da acceso a las armaduras blindadas que proporciona un aumento importante de puntos de vida de los soldados. El traje EXO con un punto de armadura es interesante para los granaderos para que soporten ellos el daño, investigando el elerio el traje WAR da dos puntos de armadura y otro adicional si tienen la habilidad de antiexplosivos, el traje de araña es útil para los francotiradores y comandos ya que tiene el gancho lo que les permite mayor movilidad y su mejora traje de espectro.

Para acceder al tercer nivel de armas y armaduras es necesario investigar el elerio.

Las investigaciones del oficial de Advent junto con la autopsia del Mec de Advent proporciona la mejora del gremblin II y la del sectópodo del gremblin III que dan más puntos de pirateo a los especialistas, muy útil para controlar unidades robóticas tanto para quitar un enemigo del campo de batalla para que además dispare y soporte daño en vez de los soldados. Al piratear algunas balizas el especialista tiene la oportuindad de aumentar permanentemente la habilidad de pirateo.

La investigación de algunas autopsias se obtienen de forma automática con la información de las las misiones por lo que realizar autopsias no es prioritario salvo las que proporcionan las mejoras anteriores, si es interesante realizar la del mutón en cuanto se pueda que proporciona el lanzagranadas avanzado y las granadas de plasma. La autopsia del lancero de Advent proporciona la espada hoja de arco. El resto de autopsias son prescindibles y lo anterior proporciona mayores beneficios.

En las investigaciones según preferencia se puede empezar por investigar las armaduras o las armas. Estas son las importantes.

  • Armas modulares

  • Armas magnéticas

  • Fusil magnético

  • Escopeta magnética

  • Pistola magnética

  • Armas gauss

  • Rifle gaus

  • Cañón magnético

  • Materiales híbridos

  • Armadura blindada

  • Traje EXO

  • Traje araña

  • Elerio

  • Rifle de plasma

  • Lanza de plasma

  • Fusil de plasma

  • Escopeta de plasma

  • Armadura potenciada

  • Traje espectro

  • Traje WAR

  • Comunicaciones

  • Radio

El orden las autopsias más importantes es el siguiente, algunas según se avanza el juego se obtienen de forma automática, la del mutón es importante ya que es una mejora considerable para el granadero más que su mejora de arma magnética, también las que proporcionan las mejoras para los gremblins.

  • Autopsia mutón
  • Lanzagranadas avanzado
  • Granada de plasma
  • Explosivos avanzados
  • Autopsia oficial Advent
  • Autopsia mech Advent
  • Gremblin II
  • Autopsia sectópodo
  • Gremblin III
  • Elerio

Construcciones

La primera construcción a realizar es la escuela táctica de guerrilla que permite entrenar a los reclutas en una especialización deseada para tener un ejército equilibrado de soldados y poder cubrir las bajas y heridas de misiones anteriores. Sobretodo y más importante permite además la gran mejora de ampliar el pelotón de 4 a 5 y 6 componentes con las tácticas de pelotón I y pelotón II, que es un mejora determinante ya que es un disparo más o dos por turno. El segundo aumento de tamaño de pelotón se consigue cuando un soldado llega al rango de capitán.

La sala de comunicaciones de la resistencia es necesaria para poder entrar en contacto con otras regiones. La sala de campo de pruebas también es importante ya que permite desarrollar los trajes EXO que tienen puntos de armadura para los granaderos, con posterioridad en importancia opcionalmente las municiones experimentales.

Los relés de energía son necesarios construirlos para dotar de energía al resto de edificios, si se emplazan en las salas de bobina de energía proporcionan mucha mayor cantidad de energía. Cómo están mejor ubicados en determinadas salas del Avenger conviene ir limpiando salas hasta llegar a una sala con bobina de energía con dos salas de energía es suficiente e incluso en una de ellas no es necesario una bobina de energía.

El centro de guerra avanzada, el taller y el laboratorio son opcionales, respectivamente permiten reentrenar las habilidades de los personajes que sabiendo que mejoras adquirir según aumentan de rango es innecesaria, también permiten curar a los soldados en la mitad de tiempo el útil pero con tres soldados por especialidad no es imprescindible, en las batallas siempre es posible volver a cargar la partida si un soldado ha sufrido mucho daño. El taller permite crear gremblins para poner en salas adyacentes en sustitución de ingenieros y el laboratorio realizar las investigaciones en menos tiempo.

  • Escuela de tácticas de guerrilla: aumento de tamaño de pelotón, entrenar soldados y otras habilidades.
  • Campo de pruebas
  • Relé de energía: con las dos construcciones anteriores ya se necesita un relé, ubicado en una sala con bobina de energía proporciona mayor cantidad de energía, para ubicar los relés en una bobina hay que planificar con antelación para ir limpiando las salas necesarias para cuando sean necesarios, el segundo relé de energía cuando sea necesario también usando los ingenieros para ir limpiando las salas hasta la que tiene la segunda bobina de energía.
  • Comunicaciones de la resistencia
  • Cámara de sombras: es necesaria para completar las investigaciones de la campaña principal y llegar al final del juego.

Otras mejoras interesantes que proporciona la escuela tácticas de guerrilla son:

  • Tirador preciso: Tiro certero
  • Granadero: Mayores explosiones
  • Especialista: Tranquilo bajo presión
  • Comando: Instintos de cazador
  • Buitre: que da un objeto adicional en los botines que dejan caer los enemigos cuando mueren.
  • Trabajo delicado: un +25% de experiencia adicional por cada muerte.

La instalación de defensa proporciona torretas en la misión en la que un ovni ataca al Avenger, 2 torretas, 4 con su mejora y dedicándole un ingeniero con mejores atributos de disparo, tampoco es imprescindible ya que solo ocurre una vez en toda la misión y no es determinante para superar la batalla.

Avenger

Avenger

Desplazamiento del AVENGER por el mapa

La tarea principal es ampliar las redes de comunicadores, instalar repetidores, recoger los recursos al inicio de cada mes, pasar por el cuartel general y el mercado negro siempre que no haya misiones encargadas por el consejo. Contactar con otras regiones dará posibilidad de desplazarse a otras regiones para iniciar misiones en las instalaciones controladas por los aliens que permitirá eliminar algún punto en el progreso del proyecto AVATAR.

Mapa del mundo

Mapa del mundo

Reclutas y soldados

En un primer momento los reclutas no tienen especialización, una vez ganan el primer ascenso con la experiencia obtenida en la batalla se puede especializar en una de cuatro clases: francotirador, granadero, especialista y comando. Cada vez que un soldado nuevamente aumenta de rango con la experiencia obtenida en los combates tiene la posibilidad de adquirir una nueva habilidad a elegir entre dos posibilidades o ramas de evolución. Los soldados tienen dos ramas de progreso dando la posibilidad tener dos vertientes distintas según la preferencia de juego o misión como el comando en sus ramas de asalto u ocultación pero en otras especializaciones una ramas es más útil que la otra, aún así cada rango permite elegir la habilidad de cualquiera de las dos ramas.

Adicionalmente, con cada nuevo rango sus estadísticas les irán aumentando, cada tipo de soldado tendrá una estadística en la que mejora más, los francotiradores en puntería, los especialistas en pirateo.

El comando de las misiones estará compuesto de al menos un tipo de soldado distinto y una vez desarrollada la posibilidad de hacer pelotones de 5 personajes o 6 poder incluir dos del mismo tipo. Con 5 soldados se pueden incluir dos tiradores o dos granaderos según se la descripción de la misión. Con seis un equipo puede estar formado por 2 francotiradores, 2 granaderos, 1 especialista y 1 comando, en algún caso está bien cambiar un francotirador o un granadero por un especialista más, pero es elegible cualquier otra combinación de especialidades distinta siempre que el grupo tenga una diversidad de especialidades para que unos se complementen a otros y sean más efectivos en los combates.

En la descripción de la misión se indica el número de enemigos que la compone y especie de esos enemigos, información útil para elegir la clase de los soldados.

Soldados granadero

El granadero es uno de los soldados más importantes ya que con sus lanzagranadas eliminar las coberturas en las que se protegen los enemigos cuando no estamos en modo oculto y los avistamos, aunque las granadas no hagan el suficiente daño para matar a los enemigos una de sus principales misiones es eliminar las coberturas en las que refugian los enemigos lanzando gradas para que el resto de soldados puedan disparar con mayor probabilidad de éxito. Sus cañones también pueden hacer mucho daño a distancias media y corta así como triturar armaduras para que igualmente el resto de soldados de otras clases inflijan más daño. También tiene la habilidad de equipar armaduras, trajes EXO y WAR, con puntos de armadura con las que el daño recibido es reducido.

Granadero

Granadero

Soldados francotirador

Están equipados con un fusil que les permite disparar a largas distancias sin exponerse a disparos de los enemigos, puede hacer mucho daño y con su característica de puntería tener mayor porcentaje de éxito aún cuando los enemigos estén protegidos por coberturas medias o completas. Todas las mejoras de arma que les permitan tener mayor puntería o pequeño mejor porcentaje de crítico les será muy útiles. Las balas trazadoras les vendrá muy bien para aumentarles mucho más su puntería. Al igual que los comandos son empleados para terminar de eliminar a los enemigos una vez que el granadero les ha desprovisto de coberturas y reducido nos cuantos puntos de vida. Tiene habilidades que cada muerte les proporciona una acción adicional con la que eliminar enemigos a los que les quede pocos puntos de vida.

Francotirador

Francotirador

Soldado especialista

Los especialistas aparte de poder disparar con su fusil tiene la misión de piratear enemigos robóticos y hacer de médicos, con los gremblins con los que van acompañados puede hacerlo a distancia. Su mejor estadística en pirateo permite tener mayor éxito. Son muy útiles para desactivar o tomar el control de enemigos robóticos ya sean mechs o torretas de forma temporal, en vez de tener que destruirlos en una primera instancia, el tomar el control de un enemigo robótico permite eliminar un enemigo y hace que este sea el que reciba el daño cuando actúen las unidades enemigas.

Especialista

Especialista

Soldado comando

Los comandos por defecto van equipados con una escopeta y una espada lo que les permite hacer mucho daño a corta distancia o cuerpo a cuerpo. Es unidad que junto con algunas de sus habilidades es empleada para terminar de matar a los enemigos heridos por los granaderos y especialistas a los que les queden o tengan pocos puntos de vida. También tienen habilidades para que dada muerte a un enemigo seguir actuando y eliminar a más de uno en el mismo turno

Comando

Comando

Soldado psi

Son una unidad adicional que se desarrolla con el laboratorio psi, no es imprescindible para finalizar el juego.

Armas complementos y Simulador de Combate Personal (SCP)

Las armas se pueden mejorar acoplándoles complementos lo que les permite tener mayor puntería o crítico con miras telescópicas, cargadores que les permiten tener un disparo más, cargas automáticas gratis, porcentaje de que la acción de disparo no cueste acción o una probabilidad de matar al enemigo independientemente de sus puntos de vida. Las miras telescópicas serán muy útiles para los francotiradores y especialistas, para los granaderos y comandos no son tan útiles ya que estos en muchas ocasiones no realizan la acción de disparar sino la acción de lanzar granadas o atacar cuerpo a cuerpo con la espada con lo que no les sacarán tanto provecho a las mejoras de las armas.

Los SCP son implantados a los soldados para mejorarles la probabilidad de esquivar, más puntos de vida, movilidad o resistencia al control de los enemigos psíquicos, en la escuela de tácticas de guerrilla se puede adquirir la guerra integrada que mejora las estadísticas de los SCP. Las habilidades de esquivar o más puntos de vida combinados con los granaderos que tienen habilidad y puntos armaduras hace que se conviertan en un soldado difícil de eliminar. A los comandos se les puede equipar con SCP también de esquivar pos si se quedan expuestos al atacar con la espada o el SCP de movilidad para moverse más lejos.

Estrategia en combates

El modo de juego suele ser equipar a los granaderos todas las granadas que puedan llevar y con sus puntos de armadura por habilidad antiexplosivos y de traje EXO les permite reducir el daño que se les inflijan, por ello los utilizo como tanques para que sean ellos los que en la medida de lo posible atraigan los disparos, los puntos de armadura les permite reducir el daño equipados con un SCP de esquivar pueden reducir aún más el daño o un SCP de +3 de vida hará que sean más difíciles de matar. Los utilizo para iniciar las emboscadas ya que en el caso de estar en modo oculto los enemigos suelen estar juntos con lo que una granada les hará daño a varios de ellos, al iniciar la emboscada el resto de soldados han de estar en modo guardia para intentar en la medida de los posible dañar a los enemigos o eliminarlos directamente, el comando puede quedarse sin activar la guardia para tener su acción después de ser descubiertos y atacar con la espada a los enemigos que queden en pie y se hayan protegido detrás de coberturas medias y completas.

Una vez se sale del modo ocultación las unidades enemigas se activan en el momento que son vistas fuera de la niebla de guerra, lo que solo permite hacer una embocada y limita la estrategia del juego quizá con alguna habilidad del especialista que permite ver a mayores distancias y del comando que puede volver a entrar en modo ocultación la estrategia sea algo diferente y se pueda hacer más de una emboscada por misión.

Los especialistas los utilizo para disparar, piratear enemigos robóticos y curar según sea necesario en cada momento. Los francotiradores ha de posicionarse en las alturas de los edificios para tener mayor porcentaje de éxito de disparo y aprovecha su largo alcance. Los comandos son útiles para atacar cuerpo a cuerpo con la espada o a corta distancia con la escopeta a un enemigo que se ha quedado protegido por una cobertura siempre intentando que una vez realizado el ataque se quede él a su vez en cobertura ya que como se adentran en las posiciones enemigas en el siguiente turno puede recibir algún ataque si quedan más enemigos.

JuegoJuego

Juego

Guardado del progreso

Al iniciar un combate, al entrar en la batalla y en varios pasos de la misma conviene hacer un guardado del juego, para que si se comete un error o por mala estadística poder volver a un punto anterior, no conviene perder soldados o acabar con heridas graves en todos más si ya tiene rangos altos. Es muy fácil que en un mal movimiento o en acierto del enemigo acabe por matar a un soldado.

En el modo de juego difícil y hombre de hierro supone una dificultad adicional ya que el guardado y progreso se realiza automáticamente por lo que una mala decisión o estrategia quizá suponga un error fatal para el resto de la campaña que de termine su fracaso.

XCOM Wiki

En la Wiki de XCOM 2 de Fandom están recogidos con detalle las armas, armaduras, habilidades de de las clases de soldados así como armas, armaduras y elementos de utilidad. Esta información resulta muy útil para elegir la que consideremos la mejor estrategia o revisarla si no es del todo efectiva.

Gameplay

Pantalla de cargaPantalla de cargaPantalla de carga

Pantallas de carga

Ingeniera ShenDoctor Shen

Ingeniera Shen y Doctor Tygan

Banda sonora original


Variable not found: Enlaces interesantes 389

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

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

Variable not found: Cómo documentar y generar código cliente de nuestras APIs utilizando Swagger/OpenAPI

$
0
0
Open API Días atrás veíamos cómo utilizar Swashbuckle para generar automáticamente la descripción OpenAPI de APIs creadas con ASP.NET Core MVC y ponerlas a disposición de los consumidores en una ruta específica:
  Descripción OpenAPI de una API

En este post vamos a ver un par de formas de sacar provecho de esta descripción:
  • En primer lugar, usaremos Swagger UI para generar un sitio web interactivo de documentación y pruebas de nuestra API.
  • Después, veremos cómo generar desde Visual Studio código cliente para acceder a la API.

Swagger UI

Swagger UI es un proyecto open source que permite generar una web de documentación partiendo de la descripción OpenAPI de un servicio. Además esta web es interactiva, pues incluye la posibilidad de probar "in situ" las llamadas a los servicios.

Ponerlo en marcha es trivial: una vez tenemos instalado el paquete Swashbuckle.AspNetCore en nuestro proyecto y hemos configurado apropiadamente la generación de la definición OpenAPI (ya lo vimos en el post anterior), basta con añadir al pipeline el middleware encargado de generar la web:
...
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/api/swagger.json", "Awesomic calculator");
});
...
Fijaos que el endpoint que especificamos en la llamada a SwaggerEndpoint() es la ruta hacia la descripción OpenAPI de nuestro servicio.

Hecho esto, ya podemos utilizar la ruta "/swagger" para tener acceso a la documentación interactiva de la API:

Página de la API Calculator en Swagger UI

Pulsando sobre las operaciones del servicio de cálculo podemos acceder a la descripción completa de las mismas. Ahí encontraremos la información textual incluida en comentarios XML en el código, los parámetros de entrada, respuestas HTTP posibles, etc:

El servicio Divide en Swagger UI
Tipos de respuesta del servicio

Para probar en vivo el servicio, podemos pulsar el botón "Try it out"; podremos especificar el valor para los distintos parámetros de entrada, y acceder después a la información retornada desde el mismo:

Probando en vivo el servicio a través de Swagger UI

Generación de código cliente para acceder a la API

Visual Studio incluye herramientas para la generación de código cliente de las APIs definidas mediante OpenAPI. He de decir que a veces parecen no funcionar demasiado bien, pero al menos cumplen mínimamente su objetivo de ahorrarnos trabajo a la hora de implementar clientes de las API.

La generación se realiza partiendo de los esquemas JSON que describen los servicios, que pueden encontrarse ya en nuestro proyecto, o bien ser descargados utilizando el IDE, accediendo a la opción Dependencies > Add Connected Service > Service References; desde ese punto podremos añadir servicios OpenAPI simplemente indicando su ruta en el disco o la URL de su definición:

Añadir referencia a servicio OpenAPI

Tras ello, Visual Studio acudirá al origen indicado, descargará el archivo y lo añadirá al proyecto en la carpeta OpenAPI estableciendo su Build action a "OpenAPI file reference", lo cual asegurará que el cliente sea generado de forma automática:

Esquema OpenAPI añadido
Si, en lugar de dejar que Visual Studio descargue el esquema y lo incluya en el proyecto, preferimos incluirlo nosotros manualmente, para que todo funcione obligatoriamente tendremos que modificar la Build Action a la indicada.
En las propiedades del archivo JSON podemos establecer también determinadas opciones, como el nombre de la clase generada o el espacio de nombres en el que será incluida. En nuestro caso, podría ser razonable establecer el nombre de la clase generada y, opcionalmente, el namespace:

Esquema OpenAPI añadido

Es importante tener en cuenta que las clases generadas serán ubicadas en la carpeta "Obj" del proyecto, por lo que no estarán disponibles a nivel de código en la solución.

Una vez realizados los pasos anteriores, ya podemos utilizar directamente el cliente de la API. Como vemos en el siguiente código, se trata de una clase con el nombre que hemos indicado, que instanciamos suministrándole la URL base del servicio y la instancia de HttpClient que se utilizará internamente para realizar las llamadas:
class Program
{
static async Task Main(string[] args)
{
var httpClient = new HttpClient();
var x = new CalculatorApi("https://localhost:44329/", httpClient);
var result = await x.DivideAsync(100, 10);
Console.WriteLine(result);
}
}
Publicado en Variable not found.

Picando Código: [Libro] The Rise and Fall of the Dinosaurs por Steve Brusatte

$
0
0

Después de visitar la exhibición de Tiranosaurios en el Museo Nacional de Escocia, pasé por la tienda de regalos. Con cada exhibición, la tienda vende artículos relacionados: juguetes, camisetas, libros para nínos y también libros científicos sobre el tema en particular. Entre estos libros me encontré con el de Steve Brusatte, paleontólogo cuyo trabajo podemos encontrar en la exhibición mencionada. The Rise and Fall of the Dinosaurs (El Auge y Caída de los Dinosaurios, ¡también disponible en español!) es un libro que recorre toda la historia de los dinosaurios. Desde el período Paleozoico (y un poco antes) donde gran parte de la tierra se concentraba en el supercontinente de Pangea, hasta su extinción y cómo fueron evolucionando a lo largo de sus millones de años de dominio sobre el planeta.

Es un libro extremadamente entretenido, está basado en descubrimientos científicos y datos, pero todo está contado desde la experiencia del autor a través de historias. Así que no es totalmente académico, lo cual podría resultar aburrido, a pesar de estar basado en conocimiento científico.

The Rise and Fall of the Dinosaurs - Steve Brusatte

 

¡Hay mucho para aprender! Por más que sepamos sobre dinosaurios y otros animales prehistóricos la paleontología está en constante evolución. Particularmente estos días se encuentra -en promedio- una especie nueva de dinosaurio por semana (dato que aprendí en el libro). Así que es una buena forma de refrescar conocimientos y estar al tanto de las última teorías sobre la evolución en la tierra.

Entre las anécdotas e historias interesantes, el autor habla sobre cómo se descubrió el Herrerasaurio en Argentina. Fue en el Valle de la Luna en la provincia de San Juan. Tengo grabado ese lugar en la memoria de haber leído sobre fósiles en alguna de las revistas científicas que leía cuando era chico (Conozca Más, Descubrir, Muy Interesante). Pero habiendo sido “fanático de los dinosaurios” desde chico, fue un nombre familiar que me hizo conectar lo nuevo que estaba leyendo con algo muy específico del pasado. También cuenta la historia sobre una expedición a la Isla de Skye en Escocia que me resultó particularmente entretenida. Voy a tener que ir, visitar el museo del que habla y salir a explorar para buscar huellas o fósiles de dinosaurios.

En el libro vamos a conocer más sobre los dinosaurios, pero también aprender cómo el período Pérmico (que vino antes de los dinosaurios y terminó con una extinción muchísimo más masiva que la que mató a los dinosaurios) fue igualmente fascinante, así como lo fueron los dinosauriomorfos y otras especies. Cuando se adentra en el tema, reaviva la fascinación por los dinosaurios. ¿Por qué/cómo los Saurópodos se volvieron tan grandes? ¿Cómo podemos imaginarlos o concebir animales de tal tamaño? Los capítulos sobre los Tiranosaurios, el T-Rex y toda su familia, son fascinantes y alimentan todavía más la admiración por la especie y dejan ver el amor incondicional que varios estudiosos le tienen a ésta especie. Es esa magia que tienen los dinosaurios, fueron animales reales, con características muy distintas y muy similares a los animales de hoy, pero sólo podemos teorizar e imaginarlos (por ahora).

En varias oportunidades paraba de leer para ir a mi libro de referencia o a internet para aprender más sobre una especie en particular. Mi libro de referencia actual es una Enciclopedia Ilustrada por Dougal Dixon (autor escocés), con 355 especies. Pero creo que no está muy actualizado… (¡los Tiranosaurios en el libro no tienen plumas!). Una de las cosas que disfruto de leer libros científicos es que me hace pensar en cosas que de repente no me hubiera cuestionado antes. Fue así que en un momento empecé a plantearme, ¿cómo carajos en algún punto de la historia un animal de repente empezó a volar? ¿Cómo se llegó hasta ahí? Específicamente qué cambió para que un animal terminara recorriendo los cielos. Potencialmente el autor haya plantado la semilla de esa idea a propósito, porque el capítulo 8 “Los dinosaurios toman vuelo” encontramos respuestas a esas preguntas.

Siguiendo con el tema de vuelo, desde que se introdujo masivamente la teoría de que los pájaros habían evolucionado de los dinosaurios tengo una nueva apreciación por éstos animales. Pero no sólo evolucionaron de los dinosaurios, son dinosaurios modernos, evolución de aquellos que sobrevivieron la extinción. Y es otra cosa interesante que reafirma el libro, los tenemos acá revoloteando entre nosotros.

Steve Brusatte se para en los hombros de gigantes, algo intrínseco en el mundo científico. Pero el autor lo demuestra en cada oportunidad que tiene. Referencia y reconoce a colegas y amigos del rubro a lo largo de todo el libro. Incluso me quedé con uno o dos títulos que menciona para buscar y leer más adelante.

El Auge y Caída de los Dinosaurios es un excelente libro que nos enseña lo último en materia de dinosaurios en un mundo post Jurassic Park. Lo recomiento ampliamente si alguna vez le gustaron o todavía le gustan los dinosaurios. Si disfrutaron cualquiera de las películas de Jurassic Park, probablemente disfruten este libro. Léanlo aunque sea por corregir las inexactitudes científicas que nos hicieron creer las películas, como que un T-Rex no nos vería si nos quedamos quietos. Si les interesa la ciencia, los animales, y la historia de nuestro planeta, probablemente también disfruten este libro.

Steve Brusatte nació en Illinois, Estados Unidos pero vive en Escocia dando clases en la Universidad de Edimburgo. Pueden seguirlo en Twitter en @SteveBrusatte. Les recomiendo buscar el libro en su biblioteca o librería favorita, y como comentaba antes, está disponible también en español.

Navegapolis: Adapte los modelos ágiles a lo que funciona para usted y su cultura.

$
0
0
No copie modelos
  • No copie los métodos y prácticas de otras empresas, ni implemente un modelo diseñado por expertos. Estudie y aprenda de ellos, pero experimente y adáptese a lo que funciona para usted y su cultura.
  • No contrate a una gran empresa de consultoría para transformar su organización de manera expédita o para implementar nuevas metodologías o prácticas... sus equipos no desarrollarán la confianza o la capacidad de sostener, continuar mejorando o adaptar y desarrollar nuevos procesos y comportamientos por su cuenta.
  • Desarrolle sus propios coaches. Inicialmente puede que necesite contratar a un coach externo para establecer una base sólida, pero en última instancia el agente del cambio debe ser propio. La intensidad del coahing es clave para el mantenimiento y el crecimiento.


A estas conclusiones llegan Nicole Forsgren, Jez Humble y Gene Kim en 2017 tras analizar durante 4 años el trabajo en 2.000 organizaciones TIC, comprendiendo desde pequeñas startups de menos de 5 empleados, hasta grandes compañías de 10.000 y cuyos resultados publican en su libro Accelerate.

 

Navegapolis: No copie los modelos ágiles de los expertos o de otras empresas

$
0
0
No copie modelos
  • No copie los métodos y prácticas de otras empresas, ni implemente un modelo diseñado por expertos. Estudie y aprenda de ellos, pero experimente y adáptese a lo que funciona para usted y su cultura.
  • No contrate a una gran empresa de consultoría para transformar su organización de manera expédita o para implementar nuevas metodologías o prácticas... sus equipos no desarrollarán la confianza o la capacidad de sostener, continuar mejorando o adaptar y desarrollar nuevos procesos y comportamientos por su cuenta.
  • Desarrolle sus propios coaches. Inicialmente puede que necesite contratar a un coach externo para establecer una base sólida, pero en última instancia el agente del cambio debe ser propio. La intensidad del coahing es clave para el mantenimiento y el crecimiento.


A estas conclusiones llegan Nicole Forsgren, Jez Humble y Gene Kim en 2017 tras analizar durante 4 años el trabajo en 2.000 organizaciones TIC, comprendiendo desde pequeñas startups de menos de 5 empleados, hasta grandes compañías de 10.000 y cuyos resultados publican en su libro Accelerate.

 

Blog Bitix: 10º aniversario del blog

$
0
0

Hugo

“Bueno, ¡pues ya está!, ya tengo mi propio blog, todavía está en fase de construcción así que según vaya teniendo tiempo iré haciendo pequeños cambios en los gadgets y en su disposición. Por ahora me conformo con tenerlo visible […]. Pero lo principal, escribir entradas en el blog, es algo que ya puedo realizar. Tratarán sobre temas relacionados con el software libre, incluyendo las dos distribuciones GNU/Linux que en este momento uso más habitualmente que son Ubuntu y Arch Linux, temas de tecnología, quizá temas de programación, experiencias personales sobre los mismos y otras cosas que se me vayan ocurriendo. […]".

Con el texto anterior empezaba el primer artículo a modo de prestación en elblogdepicodev en el 2010, este mes de febrero se cumple que hace 10 años creé y empecé a escribir en un blog, durante todo este tiempo habrá habido pocas semanas de las 520 que no he escrito al menos un artículo, es más el total de artículos que he escrito desde entonces ha sido de unos 650 artículos dado que algunas semanas he publicado dos artículos y algunas esporádicamente incluso tres. En total 2,5 millones de páginas vistas, 525K en el último año. Cuando miro Google Analytics y veo artículos del año 2017, 2016, 2015, 2014, … que se siguen visitado, no me da la sensación de que hayan pasado varios años desde que los publique.

Pasados estos 10 años y a pesar del tiempo que requiere escribir y publicar cada artículo aún sigo con ganas de seguir escribiendo y publicando, hay una enorme cantidad de temas interesantes sobre los que escribir, no me he planteado dejarlo, y es que me permite seguir aprendiendo cada semana un poco sobre alguna cosa que me interesa, me gusta compartir con la intención de que a alguien le resulta útil el contenido y quizá en un futuro esto mismo que escribo me resulte útil laboralmente. La temáticas principales siguen siendo Java y GNU/Linux aunque no es un blog solo de Java ni un blog solo de GNU/Linux. Como blog personal en el sentido de individual que es, muy rara vez incluyo información personal, en él ocasionalmente hago desempaquetados de los productos que compro y he probado, algún artículo de opinión o desde hace unos meses que tengo una PS4 escribiré sobre los juegos que voy jugando y completando.

Como comentaba en la última hemeroteca del año 2019 el blog no ha crecido en visitas a pesar de haber escrito unos 80 artículos nuevos, por ello quiero hacer algunos cambios. El primero es planificar mejor el contenido que escribo y publico con el objetivo en parte de atraer más visitas que al mismo tiempo sean interesantes de leer pero también manteniendo que el escribir lo sea para mi. Hasta ahora he escrito de lo que me ha apetecido en cada momento de forma un tanto aleatoria sin ningún plan de publicación incluso para las series de artículos relacionados como la serie de Docker o la serie sobre GraphQL. Analizando los artículos más vistos alguno de los más sencillos son los más populares de mi blog como 4 formas de hacer un bucle for en Java, me plantearé escribir según se me vayan ocurriendo alguno de estos artículos sencillos, básicos o no sencillos pero esenciales que en algún caso no escribo por ya darlo por sabido. Tampoco quiero dejar de escribir por completo de vez en cuando algún artículo que para mi considero avanzado.

El segundo punto que ya he empezado, es hacer algunas modificaciones en los estilos del blog para mejorar el porcentaje de rebote, que creo es muy alto casi de un 90%, y aumentar el número de páginas vistas por sesión. Para esto tengo pensado modificar las páginas de lista de artículos como en la página de inicio y los artículos relacionados al final de cada artículo. En vez de que sean un simple enlace que sean el título y una imagen que traigan algo más la atención a dos o tres columnas en vez de a una solo para que quepan más en lugar de un artículo en el mismo espacio. Quizá incluiré en algunas páginas un slider que incluya artículos que considero destacables también para mejorar el porcentaje de rebote y para que artículos antiguos sean un poco más visibles. También mejorar la página de error 404 con estas mismas ideas, que aunque no debería llegarse a ella si se realizan algunas visualizaciones, ahora solo muestro un mensaje sin ningún enlace salvo los de la estructura de la página.

Esos son los estilos por los que ha pasado el blog.

El blog de pico.dev con BloggerBlog Bitix con OctopressBlog Bitix con Hugo

Rediseños por los que he ido realizando en el blog

Algunas otras modificaciones ya he realizado, una de ellas crear la versión de páginas AMP del blog para ver que resultado da. En un principio esta versión está mejor adaptada para los móviles, siendo más rápida, con lo que para Google es posible que la considere mejor, y dado que Google es la mayor fuente de usuarios quizá se note algo. Al final de año mediré con Analytics cual ha sido el resultado. En las primeras semanas algunos usuarios ya están accediendo a la versión AMP.

Otra modificación importante que he realizado ha sido cargar las imágenes, los comentarios de Disqus e iframes como vídeos de YouTube con lazy load. Así estos elementos no se soliciten hasta que realmente sean necesarios al ser visualizados, lo que hace que la página se cargue antes y sea más rápida. Mejora la métrica de PageSpeed y Google en su algoritmo de posicionamiento es posible que las posicione mejor en su página de resultados.

Con algunas nuevas capacidades de Hugo como los render hooks de enlaces e imágenes es posible implementar cierta lógica para algunas cosas interesantes que simplifiquen la generación del contenido. Aún estoy pendiente de que Hugo permita usar el formato de imágenes WebP y soporte watermarking.

Vamos a ver que ocurre en la década del 2020.

Blog Bitix: Programación orientada a aspectos con AspectJ, Spring AOP y la clase Proxy

$
0
0

Los aspectos permiten separar código con distintas funcionalidades y centralizar un código común que sin utilizarlos está repartido por toda la aplicación. Son un concepto potente y una vez entendidos sus conceptos ofrecen muchas posibilidades para simplificar el código y mejorar su mantenimiento. Hay varias posibilidades, dos de las más utilizadas son AspectJ y Spring AOP, en el caso de que estas no se puedan utilizar el JDK incluye la clase Proxy para usos básicos aunque más limitados.

Java

Ciertas funcionalidades son transversales y están repartidas por toda la aplicación. Añadir y mezclar el código de esta funcionalidades con el código en los métodos hace que el código del método sea más complicado incluso puede que ese código de utilidad sea de mayor tamaño que el fundamental del método.

Algunos ejemplos de funcionalidades transversales son trazas, métricas de rendimiento, seguridad, caches o transacciones. La programación orientada a aspectos permite extraer este código transversal y aplicarlo en aquellos puntos de la aplicación donde sea necesario sin estar mezclado con el código al que se aplica. Esto facilita la legibilidad del código, su mantenimiento y la separación con conceptos.

La programación orientada a aspectos se usa mucho en las aplicaciones que usan Spring pero hay otras librerías que lo permiten, incluso el propio JDK tiene alguna clase sin necesitar de dependencias adicionales.

La programación define varios términos:

  • Aspect: es una funcionalidad genérica aplicable a múltiples objetos. Cada aspecto trata una sola funcionalidad.
  • Join point: es el punto de ejecución donde se puede aplicar un aspecto como la llamada a un método, su retorno o el acceso a una propiedad.
  • Advice: es la acción que se realiza en un pointcut.
  • Pointcut: es una expresión que busca joint points, tiene un advice asociado que se ejecuta en todos los joint points que concuerdan con la expresión.
  • weaving: proceso que aplica los aspectos a las clases, puede ser en tiempo de compilación o en tiempo de ejecución.

Esta es una clase normal con un método en la que a modo de ejemplo en la llamada al método se le apliquen dos aspectos, uno para añadir una traza cuando se llame al método y su valor de retorno y otro aspecto para medir cuando tiempo tarda en ejecutarse. La clase Foo descnoce los aspectos que se van a aplicar, no hay que hacer ninguna modificación en ella ni para añadirle los aspectos ni para quitarselos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
packageio.github.picodotdev.blogbitix.aspects;importjava.util.Random;publicclassFooimplementsIFoo{    publicvoidecho(){        System.out.println("echo");    }    publicintsum(inta,intb){        returna+b;    }    publicvoidsleep(){        try{            longtime=newRandom().nextInt(1500);            Thread.sleep(time);        }catch(Exceptione){}    }}
Foo.java

La interfaz solo es necesaria para un aspecto implementado con la clase Proxy de Java.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
packageio.github.picodotdev.blogbitix.aspects;importjava.util.Random;publicinterfaceIFoo{    voidecho();    intsum(inta,intb);    voidsleep();}
IFoo.java

Se recomienda usra la forma más simple que sea suficiente para las necesidad de la aplicación. Spring AOP es más simple que usar AspectJ y no hay necesidad de aplicar el compilador de AspectJ en el proceso de compilación. Si solo se necesita aplicar advices en la ejecución de métodos de beans de Spring, Spring AOP es suficiente.

Si no se usa spring o se necesitan aplicar aspectos en objetos no gestionados por el contenedor de Spring (como objetos de dominio) o aplicar advices en joint points distintos a las ejecuciones de métodos, por ejemplo para la obtención o asignación de una propiedad entonces la opción a usar es AspectJ.

Programación orientada a aspectos con AspectJ

AspectJ es una librería específica y la que más posibilidades ofrece de las que muestro en el artículo. Hay varias formas de utilizar AspectJ, la de usarla mediante anotaciones es bastante simple.

Una de las ventajas de AspectJ es que no requiere usar Spring para utilizarla pero para ello en el momento de compilación hay que realizar un proceso denominado weaving para añadir la funcionalidad de los aspectos que transformar el bytecode de las clases. Aplicar los aspectos transformando el código permite que los aspectos no penalicen en tiempo de ejecución y ofrezca mejor rendimiento que Spring AOP, aunque el rendimiento no es algo determinante en la mayoría de los proyectos. Por contra es más compleja y requiere aplicar a las clases un proceso de postcompilación.

Las expresiones de los ponintcuts son similares a una definición de la firma del los métodos, ámbitos de visibilidad, tipos de parámetros y tipo de retorno además del paquete. Es posible hacer expresiones boleanas compuestas para hacer más especifica una expresión. Este pointcut se aplica en la ejecución del método sum de la clase Foo que recibe dos parámetros de tipo int y retorna un valor de tipo int.

1
execution(int Foo.sum(int,int))
pointcut.txt

En la clase Aspects se definen los aspectos con una colección de pointcuts con sus código de advice asociado.

 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
packageio.github.picodotdev.blogbitix.aspects;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.After;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;importorg.aspectj.lang.annotation.Around;@AspectpublicclassAspects{    @Before("execution(void Foo.echo())")    publicvoidechoStart(){        System.out.println("aspect echo begin");    }    @After("execution(void Foo.echo())")    publicvoidechoEnd(){        System.out.println("aspect echo end");    }    @Around("execution(int Foo.sum(int,int))")    publicObjectlog(ProceedingJoinPointpjp)throwsThrowable{        System.out.println("aspect sum begin");        Objecto=pjp.proceed();        System.out.println("aspect sum end: "+o);        returno;    }    @Around("execution(void Foo.sleep())")    publicvoidtime(ProceedingJoinPointpjp)throwsThrowable{        longstart=System.currentTimeMillis();        Objecto=pjp.proceed();        longend=System.currentTimeMillis();        System.out.println("aspect time: "+(end-start));    }}
Aspects.java

Con la herramienta de construcción Gradle hay que incluir un plugin para aplicar el proceso de weaving. El proceso de weaving consiste en aplicar los aspectos a las clases, AspectJ lo realiza en tiempo de compilación modificando el bytecode de las clases en un segundo paso de compilación, con anterioridad el compilador de Java ha transformado el código fuente de las clases en bytecode.

1
2
3
4
5
6
7
plugins{    id'java'    id'application'    id'org.springframework.boot'version'2.2.4.RELEASE'    id'io.freefair.aspectj.post-compile-weaving'version'4.1.6'}...
build-1.gradle
 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
packageio.github.picodotdev.blogbitix.aspects;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.CommandLineRunner;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.EnableAspectJAutoProxy;@SpringBootApplication@EnableAspectJAutoProxypublicclassMainimplementsCommandLineRunner{    ...    @Override    publicvoidrun(String...args)throwsException{        // AspectJ
        System.out.println("");        System.out.println("AspectJ");        Foofoo=newFoo();        foo.echo();        foo.sum(3,7);        foo.sleep();        ...    }    publicstaticvoidmain(String[]args){        SpringApplication.run(Main.class,args);    }}
Main-1.java

En la salida del programa para el apartado de AspectJ se observa que el código de los aspectos se ejecuta al llamar a los métodos de la instancia de la clase Foo.

1
2
3
4
5
6
7
AspectJ
aspect echo begin
echo
aspect echo end
aspect sum begin
aspect sum end: 10
aspect time: 546
System.out-1

Programación orientada a aspectos con Spring AOP

Spring incluye su solución para la programación orientada a aspectos, más limitada que AspectJ pero suficiente para la mayoría de los casos tampoco requiere aplicar el proceso weaving de AspectJ en tiempo de compilación. La limitación de Spring AOP es que los joint points solo pueden ser métodos. Utiliza las mismas anotaciones de AspectJ para aplicar los aspects en tiempo de ejecución.

Otra diferenia con AspectJ es que los aspectos se aplican usando proxys que son una clase que envuelve a la instancia a la que se le aplica el aspecto, una vez dentro de la clase objetivo si se llama a otro método de forma interna a ese otro método no se le aplica su aspecto.

Suponiendo una clase que tiene un méodo foo y bar y desde fuera se llama a foo y este llama a bar para que en llamada desde foo a bar se apliquen los aspectos de bar hay que usar este código. Usar este código implica poner en el código una dependencia a Spring, lo cual no es deseable para el código de dominio.

1
2
3
4
5
...publicvoidfoo(){((Foo)AopContext.currentProxy()).bar();}...
SpringProxy.java

En el proxy es donde se ejecuta el código del advice.

Llamada a un método normalLlamada a un método con un proxy

Llamada a un método normal y con un proxy

Para que Spring procese las anotaciones require usar la anotación @EnableAspectJAutoProxy y que Spring encuentre la clase de los aspectos, anotándola con @Component o devolviendo una instancia en el contenedor de dependencias como en este caso.

 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
packageio.github.picodotdev.blogbitix.aspects;...@SpringBootApplication@EnableAspectJAutoProxypublicclassMainimplementsCommandLineRunner{    ...    @Bean    publicFoofoo(){        returnnewFoo();    }    @Bean    publicAspectsaspects(){        returnnewAspects();    }    @Override    publicvoidrun(String...args)throwsException{        ...        // Spring AOP
        System.out.println("");        System.out.println("Spring AOP (AspectJ anotations)");        fooBean.echo();        fooBean.sum(3,7);        fooBean.sleep();        ...    }}
Main-2.java

El plugin para realizar el proceso de weaving con AspectJ no es necesario. Spring realiza e proceso de weaving en tiempo de ejecución.

1
2
3
4
5
6
7
plugins{    id'java'    id'application'    id'org.springframework.boot'version'2.2.4.RELEASE'    //id 'io.freefair.aspectj.post-compile-weaving' version '4.1.6'
}...
build-2.gradle

El resultado es el mismo que con AspectJ.

1
2
3
4
5
6
7
Spring AOP (AspectJ anotations)
aspect echo begin
echo
aspect echo end
aspect sum begin
aspect sum end: 10
aspect time: 1049
System.out-2

Programación orientada a aspectos con la clase Proxy

Para casos muy sencillos donde no sea posible aplicar una de las opciones anteriores al no poder usar sus librerías por restricciones del proyecto en cuanto a dependencias usables está la alternativa incluida en el JDK. La clase Proxy está incorporada en el propio JDK, permite hacer cosas sencillas sin dependencias adicionales.

 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.aspects;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassLogProxyimplementsInvocationHandler{    protectedObjectobject;    protectedProxyproxy;    publicLogProxy(Objectobject){        this.object=object;        proxy=(Proxy)proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);    }    publicProxygetProxy(){        returnproxy;    }    publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{        System.out.println("proxy "+method.getName()+" begin");        Objecto=method.invoke(object,args);        System.out.print("proxy "+method.getName()+" end");        if(!method.getReturnType().equals(Void.TYPE)){            System.out.print(": "+o);        }        System.out.println();        returno;    }}
LogProxy.java
 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
packageio.github.picodotdev.blogbitix.aspects;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassProfileProxyimplementsInvocationHandler{    protectedObjectobject;    protectedProxyproxy;    publicProfileProxy(Objectobject){        this.object=object;        proxy=(Proxy)proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);    }    publicProxygetProxy(){        returnproxy;    }    publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{        longstart=System.currentTimeMillis();        Objecto=method.invoke(object,args);        longend=System.currentTimeMillis();        if(method.getName().equals("sleep")){            System.out.println("proxy time: "+(end-start));        }        returno;    }}
ProfileProxy.java

En este caso se observa que se ha aplicado el aspecto de AspectJ y además los aspectos de los proxys de este apartado.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Java Proxy
proxy echo begin
aspect echo begin
echo
aspect echo end
proxy echo end
proxy sum begin
aspect sum begin
aspect sum end: 10
proxy sum end: 10
proxy sleep begin
aspect time: 323
proxy time: 323
proxy sleep end
System.out-3

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.


Blog Bitix: Tareas básicas de administración y uso después de instalar una distribución GNU/Linux

$
0
0

Para utilizar de forma efectiva y eficiente una distribución GNU/Linux es necesario conocer las tareas básicas que hay que realizar en todo sistema. Estas son actualizar los paquetes instalados del sistema a nuevas versiones con correcciones de seguridad, correcciones de errores y mejoras, instalar y desinstalar nuevos paquetes y programas. Conocer el uso básico de la terminal permite automatizar y realizar de forma masiva algunas tareas además de también permitir actualizar el sistema e instalar y desinstalar programas.

GNU

Linux

Si has instalado recientemente o piensas instalar una distribución GNU/Linux después de elegir la distribución GNU/Linux que más se adapte a tus preferecias y de seguir los pasos para instalar una como Ubuntu, después es necesario conocer unas pocas tareas de administración del sistema. En cada distribución varía ligeramente pero en todas hay que realizar unas tareas básicas de mantenimiento.

Estas tareas básicas de mantenimiento son:

  • Actualizar los paquetes instalados del sistema. Los paquetes actualizados incluyen correcciones de seguridad por lo que es importante actualizar el sistema de forma regular. También, pueden incluir nuevas versiones de los paquetes con nuevas funcionalidades y correcciones de errores. Una programa que es necesario mantener actualizado es el navegador web, también el núcleo o kernel de Linux.
  • Instalar y desinstalar nuevos paquetes y programas. Dependiendo de las tareas que se deseen realizar hay que instalar los programas que permitan realizarlas. Para editar documentos ofimáticos, un navegador web, retocar imágenes, correo electrónico, descarga de torrents, reproductor de vídeo, reproductor de música, captura de imágenes, captura vídeo del escritorio, programas para el desarrollo y programación, virtualización, … Cada programa tienen su paquete en la ditribución que es necesario instalar para usarlo y desinstalar cuando el programa ya no se va a usar más. Es dificil que no encuentres un programa que realice lo que se desea.
  • Uso básico de la terminal. Hay programas con interfaz gráfica pero para algunas tareas es más rápido hacerlas desde la línea de comandos con la ventaja que con un script es posible automatizar en caso de ser repetitiva. Desde la línea de comandos hay numerosos programas útiles que además se pueden combinar de forma que la salida de uno sea la entrada de otro.

Dependiendo de la distribución cada una de estas tareas puede variar el comando en concreto pero en general en todas se realizan de forma similar. A continuación comento como realizar las tareas en dos de las distribuciones más populares como son Ubuntu y Arch Linux pero en Fedora, Debian, elementary OS se realizan de forma similar.

UbuntuArch Linux

Actualizar los paquetes instalados del sistema

En todas las distribuciones hay un gestor de paquetes que se encarga de forma automatizada de descargar desde los repositorios las nuevas versiones y actualizar los paquetes. Cada paquete tiene unas dependencias que el gestor de paquetes también se encarga de descargar, instalar y actualizar. Es importante realizar la actualización regularmente, todas las semanas o cada dos semanas, dado que estos incluyen importantes correcciones de seguridad, correcciones de errores o mejoras con nuevas opciones.

En Ubuntu el gestor de paquetes es apt, la actualización de los paquetes instalados a la última versión disponible en los repositorios con las correcciones de seguridad y de errores se realiza con el siguiente comando. Arch Linux también tiene su comando para realizar la actualización de todos los paquetes del sistema.

1
2
$ sudo apt update
$ sudo apt upgrade
actualizar-sistema-ubuntu.sh

Dado que Ubuntu no es una distribución rolling release sino que tiene un calendario de publicación basado en fechas planificadas cada 6 meses y de dos años para las versiones de soporte largo o LTS cuando se lanza una nueva versión de la distribución hay que actualizar la versión del sistema. Se puede instalar el sistema completo desde cero en la nueva versión o actualizar la versión instalada en el sistema a la nueva versión. En ambos casos es recomendable previamente realizar una copia de seguridad por si en el proceso se produce algún tipo de error inesperado en el raro caso de que el sistema no llegue ni siquiera a entrar al entorno de escritorio.

1
2
3
$ sudo apt update
$ sudo apt upgrade
$ sudo apt full-upgrade
actualizar-version-ubuntu.sh

En Arch Linux la actualización de los paquetes se realiza con el el siguiente comando. Dado que Arch Linux es una distribución rolling release en la que en todo momento se disponen de las últimas versiones de los paquetes y programas no hay que hacer actualizaciones a nuevas versiones de la distribución sino que esta se mantiene en constante actualización. Lo importante en Arch Linux es hacer siempre actualizaciones completas del sistema y no parciales o de un programa individualmente dado que en algún caso es posible que la versiones de los paquetes de diferentes versiones de diferentes paquetes sean incompatibles.

1
$ sudo pacman -Syu
actualizar-sistema-archlinux.sh

En el raro caso de que al actualizar un paquete en Arch Linux haya algún error se puede desactualizar a la versión anterior o hacer un downgrade.

Instalar y desinstalar nuevos paquetes y programas

Los programas y comandos permiten realizar las tareas de productividad que se deseen realizar. Para instalar nuevos programas también se utiliza el gestor de paquetes. Se puede realizar desde la linea de comandos o de forma gráfica usando el centro de software de GNOME. Basta con buscar el programa deseado y pulsar el botón instalar, la desinstalación se realiza tambíen desde el centro de Software de GNOME con el botón desinstalar.

Centro de software de GNOMEProgramas en el centro de software

Centro de software de GNOME

Si en algún momento se deja de usar un programa o se reemplaza por otro que que se considere mejor es recomendable desinstalar el antiguo lo que permite recuperar el espacio en el almacenamiento persistente que ocupe y evitar la necesidad de descargar las actualizaciones de seguridad de un programa que no se usa.

Si se trata de un programa gráfico al instalar el programa se añade un acceso directo en el lanzador de programas del entorno de escritorio como en GNOME, el entorno de escritorio KDE también tiene el suyo.

Lanzador de aplicaciones de GNOME

Lanzador de aplicaciones de GNOME

Los programas se pueden usar inmediatamente después de completar su instalación sin necesidad de reiniciar el sistema, las actualizaciones de componentes clave del sistema como el kernel se instalan pero requieren un reinicio para que sean efectivas, este reinicio se puede realizar a conveniencia del usuario sin interrumpir de manera forzosa las tareas que esté realizando.

Lanzador de aplicaciones de GNOME

Reinicio del sistema después de una actualización de software

Ubuntu tiene un proceso que se ejecuta periódicamente y notifica al usuario si hay nuevas actualizaciones en la distribución, si las hay muestra un diálogo para aplicarlas. En Arch Linux las actualizaciones se inician a petición del usuario.

Actualizar UbuntuActualizar UbuntuActualizar Ubuntu

Actualizar Ubuntu

Desde la línea de comandos el gestor de paquetes también permite instalar y desinstalar programas, basta con conocer el nombre del paquete. La base de datos de paquetes de Ubuntu y de base de datos de Arch Linux permiten hacer búsquedas por nombre, en el caso de Ubuntu hay varias bases de datos una por versión de la distribución de modo que hay que buscar en la que se tenga instalada.

1
$ apt install libreoffice libreoffice-l10n-es
instalar-programas-ubuntu.sh
1
$ sudo pacman -S libreoffice-fresh libreoffice-fresh-es
instalar-programas-archlinux.sh

El centro de software de GNOME instala los programas empaquetados con Flatpak en vez de usando los paquetes de la distribución.

Uso básico de la terminal

La línea de comandos de GNU/Linux al principio es difícil de utilizar dado que no es muy amigable al tener que conocer los comandos y sus parámetros para realizar la acción, las interfaces gráficas son más simples de utilizar dado que ofrecen una guía al usuario sin necesidad de que tenga un conocimiento previo de cómo utilizarlo.

Sin embargo, para tareas repetitivas o masivas es mas rápido y sencillo utilizar la linea de comandos conociendo el comando y los parámetros a utilizar. Un ejemplo de tarea para que se puede utilizar la línea de comandos es para convertir de forma masiva el formato de imágenes, música o vídeos.

1
2
3
$ for f in *.wav;do ffmpeg -i "$f" -acodec libmp3lame "${f%.wav}.mp3";done;
$ for f in *.wav;do ffmpeg -i "$f" -acodec libvorbis "${f%.wav}.ogg";done;
$ for f in *.mp3;do ffmpeg -i "$f" -acodec libvorbis "${f%.mp3}.ogg";done;
audio-masive-convert.sh
1
$ for f in *.mkv;do ffmpeg -i "$f" -c:v mpeg2video -c:a libmp3lame -b:v 2500K -b:a 192K -vf scale=720x406,setdar=16:9 "${f%.mkv}.mpg";done;
video-masive-convert.sh
1
2
$ for f in *.png;do convert -define webp:lossless=true"$f""${f%.*}.webp";done;
$ for f in *.jpg;do convert -define webp:lossless=false"$f""${f%.*}.webp";done;
convert-to-webp.sh

Además, los comandos se pueden componer de modo que la salida de un comando sea la entrada de otro. En este ejemplo un archivo de texto con una serie de palabras si se desea ordenar de forma ascendente y eliminar las palabras duplicadas. El comando cat lee un archivo y lo emite en su salida, sort realiza la ordenación y uniq que elimina las líneas duplicadas. La salida de un programa se conecta a la entrada de otro usando una barra vertical, |.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Lorem
ipsum
dolor
sit
amet
consectetur
adipiscing
elit
sed
eiusmod
tempor
incidunt
ut
labore
et
dolore
magna
aliqua
aliqua
texto.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ cat texto.txt | sort | uniq
adipiscing
aliqua
amet
consectetur
dolor
dolore
eiusmod
elit
et
incidunt
ipsum
labore
Lorem
magna
sed
sit
tempor
ut
sort.sh

La parte de GNU de GNU/Linux incluye una colección importante y numerosa de comandos algunos de estos son: cal, date, at, head, tail, vim, nano, sort, alias, grep, cd, chmod, chown, curl, diff, echo, find, history, kill, less, ls, man, mkdir, rmdir, mv, rm, cp, ping, pwd, ssh, sudo, tail, tar, gzip, top, iotp, uname, awk, xargs, unzip, crontab, systemd, mount, whatis, locate, uniq, seq, jq, traceroute. No es necesario conocerlos todos y sus opciones pero es muy util que existen y saber al menos que hacen, al necesitar usarlos basta con hacer una búsqueda en internet para evr un ejemplo de uso con sus opciones.

Los programas de línea de comandos ofrecen páginas de manual para aprender qué hacen, cuáles son sus parámetros y cómo utilizarlos con el comando man.

1
2
3
$ man cat
$ man sort
$ man uniq
man.sh

Cada entorno de escritorio ofrece un programa gráfico de una terminal virtual.

Terminal de GNOME

Terminal de GNOME

El intérprete de comandos es el encargado de entender las sintaxis de los comandos además de interpretar los scripts para automatizar las tareas con pequeños programas de script en vez de tener que introducir los comandos manualmente en la terminal. El intérprete de comandos Bash es un intérprete que es instalado por defecto en la mayoría de distribuciones GNU/Linux.

Que no hacer

Por muchas medidas de seguridad que implemente un sistema no son suficientes si el usuario no es consciente de algunos peligros y cosas que no se deben hacer sin saber que se está haciendo.

Lo primero es no ejecutar cualquier comando que se encuentre en internet sin saber que hace por muy curioso que sea. Un ejemplo es el comando fork bomb, este hace que pasados unos pocos segundos el sistema agote todos sus recursos, lo hace inusable y obliga ha hacer un reinicio. Y este comando no es un comando de las peores maldades que se pueden hacer.

:(){ :|:& };:

Al igual que los comandos es conveniente no ejecutar programas que no provenga de una fuente de confianza, normalmente los repositorios de software de la distribución o el centro de software. En Windows es común ejecutar cracks y activadores para usar Windows, Microsoft Office u otros programas que requieren comprar una licencia de uso. Estos programas activadores es habitual que contengan virus y una fuente de infección del sistema con un peligro para la seguridad, ya solo acceder a las páginas de baja reputación desde la que descargarlos es un peligro.

En GNU/Linux la mayor parte del software no tiene coste y está disponible en los repositorios de software, puede ser necesario descargar un programa que no se encuentre ahí pero en caso necesario hay que hacerlo siempre desde la página oficial y prestando especial atención si para ejecutarlo requiere concederle permisos de superusuario.

Blog Bitix: Tareas básicas después de instalar una distribución GNU/Linux

$
0
0

Para utilizar de forma efectiva y eficiente una distribución GNU/Linux es necesario conocer las tareas básicas que hay que realizar en todo sistema. Estas son actualizar los paquetes instalados del sistema a nuevas versiones con correcciones de seguridad, correcciones de errores y mejoras, instalar y desinstalar nuevos paquetes y programas. Conocer el uso básico de la terminal permite automatizar y realizar de forma masiva algunas tareas además de también permitir actualizar el sistema e instalar y desinstalar programas.

GNU

Linux

Si has instalado recientemente o piensas instalar una distribución GNU/Linux después de elegir la distribución GNU/Linux que más se adapte a tus preferecias y de seguir los pasos para instalar una como Ubuntu, después es necesario conocer unas pocas tareas de administración del sistema. En cada distribución varía ligeramente pero en todas hay que realizar unas tareas básicas de mantenimiento.

Estas tareas básicas de mantenimiento son:

  • Actualizar los paquetes instalados del sistema. Los paquetes actualizados incluyen correcciones de seguridad por lo que es importante actualizar el sistema de forma regular. También, pueden incluir nuevas versiones de los paquetes con nuevas funcionalidades y correcciones de errores. Una programa que es necesario mantener actualizado es el navegador web, también el núcleo o kernel de Linux.
  • Instalar y desinstalar nuevos paquetes y programas. Dependiendo de las tareas que se deseen realizar hay que instalar los programas que permitan realizarlas. Para editar documentos ofimáticos, un navegador web, retocar imágenes, correo electrónico, descarga de torrents, reproductor de vídeo, reproductor de música, captura de imágenes, captura vídeo del escritorio, programas para el desarrollo y programación, virtualización, … Cada programa tienen su paquete en la ditribución que es necesario instalar para usarlo y desinstalar cuando el programa ya no se va a usar más. Es dificil que no encuentres un programa que realice lo que se desea.
  • Uso básico de la terminal. Hay programas con interfaz gráfica pero para algunas tareas es más rápido hacerlas desde la línea de comandos con la ventaja que con un script es posible automatizar en caso de ser repetitiva. Desde la línea de comandos hay numerosos programas útiles que además se pueden combinar de forma que la salida de uno sea la entrada de otro.

Dependiendo de la distribución cada una de estas tareas puede variar el comando en concreto pero en general en todas se realizan de forma similar. A continuación comento como realizar las tareas en dos de las distribuciones más populares como son Ubuntu y Arch Linux pero en Fedora, Debian, elementary OS se realizan de forma similar.

UbuntuArch Linux

Actualizar los paquetes instalados del sistema

En todas las distribuciones hay un gestor de paquetes que se encarga de forma automatizada de descargar desde los repositorios las nuevas versiones y actualizar los paquetes. Cada paquete tiene unas dependencias que el gestor de paquetes también se encarga de descargar, instalar y actualizar. Es importante realizar la actualización regularmente, todas las semanas o cada dos semanas, dado que estos incluyen importantes correcciones de seguridad, correcciones de errores o mejoras con nuevas opciones.

En Ubuntu el gestor de paquetes es apt, la actualización de los paquetes instalados a la última versión disponible en los repositorios con las correcciones de seguridad y de errores se realiza con el siguiente comando. Arch Linux también tiene su comando para realizar la actualización de todos los paquetes del sistema.

1
2
$ sudo apt update
$ sudo apt upgrade
actualizar-sistema-ubuntu.sh

Dado que Ubuntu no es una distribución rolling release sino que tiene un calendario de publicación basado en fechas planificadas cada 6 meses y de dos años para las versiones de soporte largo o LTS cuando se lanza una nueva versión de la distribución hay que actualizar la versión del sistema. Se puede instalar el sistema completo desde cero en la nueva versión o actualizar la versión instalada en el sistema a la nueva versión. En ambos casos es recomendable previamente realizar una copia de seguridad por si en el proceso se produce algún tipo de error inesperado en el raro caso de que el sistema no llegue ni siquiera a entrar al entorno de escritorio.

1
2
3
$ sudo apt update
$ sudo apt upgrade
$ sudo apt full-upgrade
actualizar-version-ubuntu.sh

En Arch Linux la actualización de los paquetes se realiza con el el siguiente comando. Dado que Arch Linux es una distribución rolling release en la que en todo momento se disponen de las últimas versiones de los paquetes y programas no hay que hacer actualizaciones a nuevas versiones de la distribución sino que esta se mantiene en constante actualización. Lo importante en Arch Linux es hacer siempre actualizaciones completas del sistema y no parciales o de un programa individualmente dado que en algún caso es posible que la versiones de los paquetes de diferentes versiones de diferentes paquetes sean incompatibles.

1
$ sudo pacman -Syu
actualizar-sistema-archlinux.sh

En el raro caso de que al actualizar un paquete en Arch Linux haya algún error se puede desactualizar a la versión anterior o hacer un downgrade.

Instalar y desinstalar nuevos paquetes y programas

Los programas y comandos permiten realizar las tareas de productividad que se deseen realizar. Para instalar nuevos programas también se utiliza el gestor de paquetes. Se puede realizar desde la linea de comandos o de forma gráfica usando el centro de software de GNOME. Basta con buscar el programa deseado y pulsar el botón instalar, la desinstalación se realiza tambíen desde el centro de Software de GNOME con el botón desinstalar.

Centro de software de GNOMEProgramas en el centro de software

Centro de software de GNOME

Si en algún momento se deja de usar un programa o se reemplaza por otro que que se considere mejor es recomendable desinstalar el antiguo lo que permite recuperar el espacio en el almacenamiento persistente que ocupe y evitar la necesidad de descargar las actualizaciones de seguridad de un programa que no se usa.

Si se trata de un programa gráfico al instalar el programa se añade un acceso directo en el lanzador de programas del entorno de escritorio como en GNOME, el entorno de escritorio KDE también tiene el suyo.

Lanzador de aplicaciones de GNOME

Lanzador de aplicaciones de GNOME

Los programas se pueden usar inmediatamente después de completar su instalación sin necesidad de reiniciar el sistema, las actualizaciones de componentes clave del sistema como el kernel se instalan pero requieren un reinicio para que sean efectivas, este reinicio se puede realizar a conveniencia del usuario sin interrumpir de manera forzosa las tareas que esté realizando.

Lanzador de aplicaciones de GNOME

Reinicio del sistema después de una actualización de software

Ubuntu tiene un proceso que se ejecuta periódicamente y notifica al usuario si hay nuevas actualizaciones en la distribución, si las hay muestra un diálogo para aplicarlas. En Arch Linux las actualizaciones se inician a petición del usuario.

Actualizar UbuntuActualizar UbuntuActualizar Ubuntu

Actualizar Ubuntu

Desde la línea de comandos el gestor de paquetes también permite instalar y desinstalar programas, basta con conocer el nombre del paquete. La base de datos de paquetes de Ubuntu y de base de datos de Arch Linux permiten hacer búsquedas por nombre, en el caso de Ubuntu hay varias bases de datos una por versión de la distribución de modo que hay que buscar en la que se tenga instalada.

1
$ apt install libreoffice libreoffice-l10n-es
instalar-programas-ubuntu.sh
1
$ sudo pacman -S libreoffice-fresh libreoffice-fresh-es
instalar-programas-archlinux.sh

El centro de software de GNOME instala los programas empaquetados con Flatpak en vez de usando los paquetes de la distribución.

Uso básico de la terminal

La línea de comandos de GNU/Linux al principio es difícil de utilizar dado que no es muy amigable al tener que conocer los comandos y sus parámetros para realizar la acción, las interfaces gráficas son más simples de utilizar dado que ofrecen una guía al usuario sin necesidad de que tenga un conocimiento previo de cómo utilizarlo.

Sin embargo, para tareas repetitivas o masivas es mas rápido y sencillo utilizar la linea de comandos conociendo el comando y los parámetros a utilizar. Un ejemplo de tarea para que se puede utilizar la línea de comandos es para convertir de forma masiva el formato de imágenes, música o vídeos.

1
2
3
$ for f in *.wav;do ffmpeg -i "$f" -acodec libmp3lame "${f%.wav}.mp3";done;
$ for f in *.wav;do ffmpeg -i "$f" -acodec libvorbis "${f%.wav}.ogg";done;
$ for f in *.mp3;do ffmpeg -i "$f" -acodec libvorbis "${f%.mp3}.ogg";done;
audio-masive-convert.sh
1
$ for f in *.mkv;do ffmpeg -i "$f" -c:v mpeg2video -c:a libmp3lame -b:v 2500K -b:a 192K -vf scale=720x406,setdar=16:9 "${f%.mkv}.mpg";done;
video-masive-convert.sh
1
2
$ for f in *.png;do convert -define webp:lossless=true"$f""${f%.*}.webp";done;
$ for f in *.jpg;do convert -define webp:lossless=false"$f""${f%.*}.webp";done;
convert-to-webp.sh

Además, los comandos se pueden componer de modo que la salida de un comando sea la entrada de otro. En este ejemplo un archivo de texto con una serie de palabras si se desea ordenar de forma ascendente y eliminar las palabras duplicadas. El comando cat lee un archivo y lo emite en su salida, sort realiza la ordenación y uniq que elimina las líneas duplicadas. La salida de un programa se conecta a la entrada de otro usando una barra vertical, |.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Lorem
ipsum
dolor
sit
amet
consectetur
adipiscing
elit
sed
eiusmod
tempor
incidunt
ut
labore
et
dolore
magna
aliqua
aliqua
texto.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ cat texto.txt | sort | uniq
adipiscing
aliqua
amet
consectetur
dolor
dolore
eiusmod
elit
et
incidunt
ipsum
labore
Lorem
magna
sed
sit
tempor
ut
sort.sh

La parte de GNU de GNU/Linux incluye una colección importante y numerosa de comandos algunos de estos son: cal, date, at, head, tail, vim, nano, sort, alias, grep, cd, chmod, chown, curl, diff, echo, find, history, kill, less, ls, man, mkdir, rmdir, mv, rm, cp, ping, pwd, ssh, sudo, tail, tar, gzip, top, iotp, uname, awk, xargs, unzip, crontab, systemd, mount, whatis, locate, uniq, seq, jq, traceroute. No es necesario conocerlos todos y sus opciones pero es muy util que existen y saber al menos que hacen, al necesitar usarlos basta con hacer una búsqueda en internet para evr un ejemplo de uso con sus opciones.

Los programas de línea de comandos ofrecen páginas de manual para aprender qué hacen, cuáles son sus parámetros y cómo utilizarlos con el comando man.

1
2
3
$ man cat
$ man sort
$ man uniq
man.sh

Cada entorno de escritorio ofrece un programa gráfico de una terminal virtual.

Terminal de GNOME

Terminal de GNOME

El intérprete de comandos es el encargado de entender las sintaxis de los comandos además de interpretar los scripts para automatizar las tareas con pequeños programas de script en vez de tener que introducir los comandos manualmente en la terminal. El intérprete de comandos Bash es un intérprete que es instalado por defecto en la mayoría de distribuciones GNU/Linux.

Que no hacer

Por muchas medidas de seguridad que implemente un sistema no son suficientes si el usuario no es consciente de algunos peligros y cosas que no se deben hacer sin saber que se está haciendo.

Lo primero es no ejecutar cualquier comando que se encuentre en internet sin saber que hace por muy curioso que sea. Un ejemplo es el comando fork bomb, este hace que pasados unos pocos segundos el sistema agote todos sus recursos, lo hace inusable y obliga ha hacer un reinicio. Y este comando no es un comando de las peores maldades que se pueden hacer.

:(){ :|:& };:

Al igual que los comandos es conveniente no ejecutar programas que no provenga de una fuente de confianza, normalmente los repositorios de software de la distribución o el centro de software. En Windows es común ejecutar cracks y activadores para usar Windows, Microsoft Office u otros programas que requieren comprar una licencia de uso. Estos programas activadores es habitual que contengan virus y una fuente de infección del sistema con un peligro para la seguridad, ya solo acceder a las páginas de baja reputación desde la que descargarlos es un peligro.

En GNU/Linux la mayor parte del software no tiene coste y está disponible en los repositorios de software, puede ser necesario descargar un programa que no se encuentre ahí pero en caso necesario hay que hacerlo siempre desde la página oficial y prestando especial atención si para ejecutarlo requiere concederle permisos de superusuario.

Variable not found: Enlaces interesantes 390

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

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

    Web / HTML / CSS / Javascript

    Visual Studio / Complementos / Herramientas

    Xamarin / Mobile

    Otros

    Publicado en Variable not found.

    Variable not found: Publicación self-contained y single-file en .NET Core

    $
    0
    0
    .NET CoreComo sabemos, para ejecutar cualquier tipo de aplicación .NET Core en un equipo necesitamos tener instalado el runtime o el SDK de la plataforma. Esto es algo que podemos hacer muy fácilmente, simplemente acudiendo a la página oficial de descargas, eligiendo nuestro sistema operativo y siguiendo las instrucciones de instalación.

    El hecho de que en el equipo destino esté preinstalado el runtime es muy interesante, entre otras cosas porque permite asegurar de antemano que en él se encontrarán todas las dependencias (frameworks, bibliotecas, paquetes, metapaquetes) necesarios para una correcta ejecución. Por tanto, para distribuir nuestra aplicación sólo debemos generar lo relativo a nuestro código, el resto ya estará allí.
    Esta forma de publicar aplicaciones se denomina framework-dependent, pues dependen de que determinados componentes del framework estén instalado en el destino.
    Por ejemplo, el paquete de publicación de una aplicación de consola prácticamente vacía, que únicamente muestra el mensaje "Hello world!", ocuparía solo 175K:
    D:\MyConsoleApp\output>dir

    El volumen de la unidad D es Datos
    El número de serie del volumen es: 8CBC-81E3

    Directorio de D:\MyConsoleApp\output

    09/02/2020 18:47 <DIR> .
    09/02/2020 18:47 <DIR> ..
    09/02/2020 18:46 428 MyConsoleApp.deps.json
    09/02/2020 18:46 4.608 MyConsoleApp.dll
    09/02/2020 18:46 169.984 MyConsoleApp.exe
    09/02/2020 18:46 668 MyConsoleApp.pdb
    09/02/2020 18:46 154 MyConsoleApp.runtimeconfig.json
    5 archivos 175.842 bytes
    2 dirs 463.058.874.368 bytes libres

    D:\MyConsoleApp\output>_
    Otra ventaja de este tipo de distribución es que es cross platform pura, es decir, podemos copiar los archivos a cualquiera de los sistemas operativos soportados y, siempre que dispongan del runtime, nuestra aplicación podrá correr sobre ellos sin problema.

    Y todo esto está muy bien, pero, ¿qué pasa si quiero crear una aplicación portable, de forma que pueda distribuirla y ejecutarla sin necesidad de que el equipo destino tenga nada preinstalado?

    Pues eso es lo que veremos en este post ;)

    Publicación self-contained

    Este tipo de publicación incluye todo lo necesario para que la aplicación funcione, sin necesidad de que el equipo destino disponga de componentes preinstalados. Es la opción más segura si desconocemos qué runtimes están instalados en el servidor, o incluso si queremos aislarnos de cambios o actualizaciones que pudieran instalarse en el servidor y que, de alguna forma, pudieran salpicarnos en el futuro.

    Para publicar en modo self contained desde Visual Studio, sólo tendremos que acudir al perfil de publicación y editar sus settings de la siguiente forma:

    Perfil de publicación estableciendo el deployment mode a self-contained y el target runtime a win-x64

    Como se observa en la captura anterior, en el Deployment mode debemos seleccionar "Self-contained", mientras que en la opción Target Runtime tendremos que indicar el runtime sobre el que vamos a ejecutar la aplicación. Este paso es importante, pues hará que los binarios a incluir en el paquete distribuible sean los específicos para el entorno indicado.

    Esto también podemos hacerlo si queremos generar el paquete de publicación desde la línea de comandos, por ejemplo como sigue:
    D:\MyConsoleApp>dotnet publish --self-contained -r win-x64 -c release -o output

    Microsoft (R) Build Engine versión 16.4.0+e901037fe para .NET Core
    Copyright (C) Microsoft Corporation. Todos los derechos reservados.

    Restauración realizada en 138,79 ms para D:\MyConsoleApp\MyConsoleApp.csproj.
    MyConsoleApp -> D:\MyConsoleApp\bin\release\netcoreapp3.1\win-x64\MyConsoleApp.dll
    MyConsoleApp -> D:\MyConsoleApp\output\

    D:\MyConsoleApp\output>_
    En cualquier caso, el principal inconveniente de este modelo de distribución es que los archivos a mover son bastantes más, por lo que los despliegues serán más lentos y ocuparán mucho más espacio en disco. Por ejemplo, si hacemos un dir en la carpeta de resultados de la publicación veremos que hemos pasado de tener cinco archivos a más de doscientos, y el tamaño de menos de 200Kb a 69Mb:
    D:\MyConsoleApp\output>dir

    El volumen de la unidad D es Datos
    El número de serie del volumen es: 8CBC-81E3

    Directorio de D:\MyConsoleApp\output

    09/02/2020 18:56 <DIR> .
    09/02/2020 18:56 <DIR> ..
    20/04/2018 06:28 19.208 api-ms-win-core-console-l1-1-0.dll
    20/04/2018 06:28 18.696 api-ms-win-core-datetime-l1-1-0.dll
    20/04/2018 06:28 18.696 api-ms-win-core-debug-l1-1-0.dll
    20/04/2018 06:28 18.696 api-ms-win-core-errorhandling-l1-1-0.dll
    20/04/2018 06:29 22.280 api-ms-win-core-file-l1-1-0.dll
    20/04/2018 06:37 18.696 api-ms-win-core-file-l1-2-0.dll
    (... Omitidos más de 200 archivos ...)
    09/12/2019 03:39 14.928 System.Xml.XmlDocument.dll
    09/12/2019 03:40 16.768 System.Xml.XmlSerializer.dll
    09/12/2019 03:40 14.200 System.Xml.XPath.dll
    09/12/2019 03:39 15.952 System.Xml.XPath.XDocument.dll
    20/04/2018 06:37 1.016.584 ucrtbase.dll
    09/12/2019 03:40 15.440 WindowsBase.dll
    225 archivos 69.122.606 bytes
    2 dirs 462.918.475.776 bytes libres

    D:\MyConsoleApp\output>_
    Sí, pensaréis que es un exceso para mostrar un simple "Hola mundo", pero si tenemos en cuenta que estos archivos incluyen el framework y todas sus bibliotecas no sale tan mal parada la cosa. Lo importante en este caso es que podemos copiar esta carpeta a cualquier servidor Windows x64 y funcionará correctamente, sin necesidad de tener nada preinstalado.

    Pero aún podemos mejorarlo un poco...

    Eliminando peso: Trimming de paquetes

    Cuando hemos echado un ojo al contenido de la carpeta de destino de la publicación, vimos archivos como System.Xml.XmlSerializer.dll o System.Xml.XPath.dll... ¿realmente necesitamos desplegar estos ensamblados en nuestra aplicación, que sólo muestra un "Hello world!"? Seguro que no.

    Desde .NET Core 3.0, el SDK incluye de serie una funcionalidad que permite eliminar de los archivos distribuibles los paquetes que no sean utilizados por nuestra aplicación o sus dependencias. Para activarlo, basta con añadir el elemento <PublishTrimmed> en el archivo .csproj del proyecto:
    <PropertyGroup>
    <PublishTrimmed>true</PublishTrimmed>
    </PropertyGroup>
    Hecho esto, si volvemos a repetir la operación de publicación, veremos que el paquete de publicación se reducirá bastante:
    D:\MyConsoleApp>dotnet publish --self-contained -r win-x64 -c release -o output

    Microsoft (R) Build Engine versión 16.4.0+e901037fe para .NET Core
    Copyright (C) Microsoft Corporation. Todos los derechos reservados.

    Restauración realizada en 26,72 ms para D:\MyConsoleApp\MyConsoleApp.csproj.
    MyConsoleApp -> D:\MyConsoleApp\bin\Release\netcoreapp3.1\win-x64\MyConsoleApp.dll
    Se está optimizando el tamaño de los ensamblados, lo que puede cambiar el
    comportamiento de la aplicación. Asegúrese de probarlo después de publicar.
    Consulte https://aka.ms/dotnet-illink
    MyConsoleApp -> D:\MyConsoleApp\output\

    D:\MyConsoleApp>dir output

    El volumen de la unidad D es Datos
    El número de serie del volumen es: 8CBC-81E3

    Directorio de D:\MyConsoleApp\output
    09/02/2020 19:05 <DIR> .
    09/02/2020 19:05 <DIR> ..
    20/04/2018 06:28 19.208 api-ms-win-core-console-l1-1-0.dll
    20/04/2018 06:28 18.696 api-ms-win-core-datetime-l1-1-0.dll
    20/04/2018 06:28 18.696 api-ms-win-core-debug-l1-1-0.dll
    20/04/2018 06:28 18.696 api-ms-win-core-errorhandling-l1-1-0.dll
    (... Omitidos más de 50 archivos ...)
    09/02/2020 19:05 62.464 System.Console.dll
    07/12/2019 16:40 9.555.840 System.Private.CoreLib.dll
    09/02/2020 19:05 74.752 System.Runtime.Extensions.dll
    20/04/2018 06:37 1.016.584 ucrtbase.dll
    63 archivos 26.499.046 bytes
    2 dirs 462.951.739.392 bytes libres

    D:\MyConsoleApp>_
    Mucho mejor ahora: hemos pasado de 225 archivos a 63, y reducido el peso de 69 a 26Mb. Aunque sigue siendo demasiado para un simple "Hello world!", al menos sabemos que es el mínimo al que podemos aspirar si queremos que el paquete distribuible de nuestra aplicación incluya el framework sobre el que será ejecutada.

    Un último detalle: como hemos comentado anteriormente, el trimming eliminará los paquetes que detecte que no son utilizados, pero puede haber ocasiones en las que nos interesa que este mecanismo no elimine algún ensamblado en particular. Por ejemplo, si nuestra aplicación utiliza reflexión o cualquier otro mecanismo para cargar o utilizar ensamblados, el trimmer no los detectará y asumirá que no se están usando, lo que provocará errores en tiempo de ejecución.

    Para indicar que un ensamblado debe ser incluido obligatoriamente en el paquete de publicación, podemos usar el elemento <TrimmerRootAssembly> en el .csproj:
    <ItemGroup>
    <TrimmerRootAssembly Include="System.Xml.XmlSerializer.dll" />
    </ItemGroup>

    Publicación single-file: ¡un único ejecutable!

    A partir de .NET Core 3, tenemos disponible un nuevo modelo de distribución que permite incluir en un único ejecutable todo lo necesario para que nuestra aplicación funcione sin tener nada preinstalado.

    Podemos publicar como archivo único mediante una orden de la CLI como la siguiente:
    D:\MyConsoleApp>dotnet publish -r win10-x64 -p:PublishSingleFile=true -o output

    Microsoft (R) Build Engine versión 16.4.0+e901037fe para .NET Core
    Copyright (C) Microsoft Corporation. Todos los derechos reservados.

    Restauración realizada en 124,52 ms para D:\MyConsoleApp\MyConsoleApp.csproj.
    MyConsoleApp -> D:\MyConsoleApp\bin\Debug\netcoreapp3.1\win10-x64\MyConsoleApp.dll
    Se está optimizando el tamaño de los ensamblados, lo que puede cambiar el
    comportamiento de la aplicación. Asegúrese de probarlo después de publicar.
    Consulte https://aka.ms/dotnet-illink
    MyConsoleApp -> D:\MyConsoleApp\output\

    D:\MyConsoleApp>dir output

    El volumen de la unidad D es Datos
    El número de serie del volumen es: 8CBC-81E3

    Directorio de D:\MyConsoleApp\output

    09/02/2020 19:10 <DIR> .
    09/02/2020 19:10 <DIR> ..
    09/02/2020 19:10 26.501.267 MyConsoleApp.exe
    09/02/2020 19:10 680 MyConsoleApp.pdb
    2 archivos 26.501.947 bytes
    2 dirs 462.872.199.168 bytes libres

    D:\MyConsoleApp>_
    En lugar de tener que indicar tantos parámetros cada vez, también podríamos conseguirlo modificando el archivo .csproj. Para ello, bastaría con establecer a true el elemento <PublishSingleFile>, aunque al hacerlo, además, será obligatorio introducir el runtime de destino en el item <RuntimeIdentifier>. El resultado final podría ser algo así (trimming incluido):
    <PropertyGroup>
    <PublishTrimmed>true</PublishTrimmed>
    <PublishSingleFile>true</PublishSingleFile>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    </PropertyGroup>
    En cualquier caso, fijaos que podríamos distribuir la aplicación, el runtime y el framework en un único ejecutable de 26Mb (usando el trimmer).

    Publicado en Variable not found.

    Fixed Buffer: Escribiendo código de alto rendimiento en .Net Core

    $
    0
    0
    Tiempo de lectura:12minutos
    Imagen ornamental para la entrada Escribiendo código de alto rendimiento en C# con .Net Core

    Recientemente he estado en una charla de un grande del sector como es Carlos Landeras y en el clásico afterwork tras la charla, he tenido la oportunidad de hablar con el largo y tendido con el sobre el tema y finalmente me he decidido a escribir una entrada sobre cómo hacer código de alto rendimiento utilizando .Net Core.

    En primer lugar y, ante todo, hay que utilizar la cabeza y no perder tiempo en optimizar sin ser necesario. La gran mayoría de aplicaciones no necesitan de utilizar las cosas que vamos a ver a continuación, pero es conveniente saber que existen porque a veces hacen falta.

    ¿Cuándo debo mejorar el rendimiento de mis aplicaciones .Net Core?

    Lo primero que cabe preguntarse en este momento es si vale la pena optimizar nuestra aplicación, ¿Y cómo puedo decidir si vale la pena? La pregunta es difícil de resolver porque no hay una verdad absoluta al respecto, pero principalmente podemos hacernos algunas preguntas para decidir si necesitamos modificar nuestro código:

    • ¿Tiene una alta concurrencia?
    • ¿Los recursos del equipo son limitados?
    • ¿Estamos teniendo problemas con el rendimiento?
    • ¿Estamos creando una librería cuyo uso pueda caer en algún escenario de los anteriores?

    Optimizar un código tiene un coste de desarrollo extra y muchas veces no vale la pena el esfuerzo necesario para conseguirlo. No es lo mismo optimizar un método que se ejecuta una vez al arrancar nuestra aplicación, por ejemplo, que un método que se llama cientos de veces por segundo. Si estamos ejecutando nuestra aplicación en un servidor tampoco es lo mismo que, si por el contrario la estamos ejecutando en una raspberry pi por ejemplo, los recursos en un caso son ‘ilimitados’ y en el otro no. A pesar de lo anterior… ¿Estamos teniendo problemas? Podemos tener un código que se ejecuta cientos de veces por segundo en un equipo con pocos recursos, pero aun, así no existir problemas en el rendimiento.

    Si por el contrario eres de los que sí necesita optimizar tu código, agárrate que vienen curvas (aunque voy a intentar simplificarlo al máximo).

    ¿Cómo puedo saber dónde mejorar el rendimiento de mis aplicaciones .Net Core?

    La respuesta a esta pregunta es muy variada y depende de que es exactamente lo que haga el código que queremos optimizar. Por ejemplo, ¿cúal de los siguientes métodos es mejor para concatenar dos cadenas?

    public string StringConcat() => string.Concat(_stringA, _stringB);
    
    public string StringFormat() => string.Format("{0}{1}", _stringA, _stringB);
    
    public string StringInterpolation() => $"{_stringA}{_stringB}";
    
    public string StringAdd() => _stringA + _stringB;
    
    public string StringBuilder()
    {
        var builder = new StringBuilder();
        builder.Append(_stringA);
        builder.Append(_stringB);
        return builder.ToString();
    }
    

    Siempre hemos oído que hacer una operación ‘+’ entre dos cadenas es lo peor que podemos hacer ya que las cadenas son inmutables y es una mala práctica, que es mejor utilizar un StringBuilder pero… ¿Serías capaz de decir de las 5 opciones cual es mejor y cual peor sin ser meras suposiciones?

    Para poder optimizar cualquier parte del código, lo primero es medirlo. Si no tomamos métricas sobre los recursos que está utilizando un código, todo lo que hagamos serán meras suposiciones. Precisamente para temas como este, hace unos meses hablábamos sobre como medir el rendimiento de nuestro código utilizando BenchmarkDotNet y hoy vamos a recuperar la utilidad que ofrece para hacer precisamente eso, medir. No es posible optimizar código sin hacer diferentes mediciones que nos digan si estamos haciendo que las cosas vayan mejor o peor. Por ejemplo, sin medir nada, podemos pensar que lo mejor tal vez sea concatenar (el método StringConcat) o tal vez usar un StringBuilder, y que el peor quizás sea hacer una simple suma (el método StringAdd). Cuando hacemos un benchmark de esos cinco métodos, los resultados tal vez sorprendan a más de uno…

    La imagen muestra los resultados para el código anterior donde los resultados dicen que StringConcat tarda 23 ns, StringFormat 118 ns, StringInterpolation 24 ns, StringAdd 23 ns y StringBuilder 49 ns,

    Sin ánimo de venir a decir ahora que hacer suma de cadenas ya no es un problema (que sí lo es), lo que pretendo mostrar es que siempre es necesario medir para poder determinar dónde está el problema. En el caso anterior al ser solo dos cadenas y una única repetición, el caso de sumar cadenas no tiene impacto mientras que otros métodos pueden costar hasta 5 veces más, si estuviésemos haciendo esto en ciclos largos (por ejemplo 1000 veces) donde se haga la cadena A unida a la B y el resultado a la B evidentemente los resultados serían muy distintos:

    La imagen muestra los resultados para el código anterior repetido 1000 veces donde los resultados dicen que StringConcat tarda 648 ns, StringFormat 1922 ns, StringInterpolation 616 ns, StringAdd 610 ns y StringBuilder 11 ns,

    En este caso, solo nos hemos fijado en el tiempo de ejecución, pero… ¿Y la memoria? ¿Puede una mala gestión de memoria ser un problema que nos haga perder rendimiento en una aplicación .Net Core? La verdad es que sí. Por cómo trabaja .Net en general, la memoria la maneja una herramienta conocida como el Garbage Collector.

    ¿Cómo funciona el Garbage Collector en .Net Core?

    El recolector de basura es una herramienta que utilizan lenguajes como C# o Java para gestionar la memoria de la aplicación. Básicamente el recolector se encarga de hacer las reservas de memoria cuando creamos un nuevo objeto por referencia. El concepto de la gestión de memoria en .Net es un tema complejo y muy interesante y saber sobre él nos permite generar código con mucho mejor rendimiento.

    La memoria se divide en dos secciones diferentes con diferentes finalidades.

    • Stack (Pila)
    • Heap (Montón)

    La pila es el lugar donde se almacenan las variables por valor (struct) mientras que el montón es donde se almacenan las variables por referencia (class).

    Esto no es siempre así como plantearemos más adelante pero de momento podemos asumir que sí.

    La pila es ‘reducida’ pero muy rápida y no es manejada por el recolector de basura mientras que el montón es más grande y si lo gestiona el recolector de basura y tiene una manera muy especial de hacerlo. De cara a optimizar el proceso de limpieza, .Net divide los objetos del montón en 3 generaciones, siendo la generación 0 la de los objetos más efímeros y la generación 2 la de los objetos más longevos de la aplicación.

    El recolector de basura es quien se encarga de asignar la memoria cuando creamos nuevos objetos por referencia, pero no siempre tiene esa memoria disponible. Cuando no tiene suficiente memoria libre para darnos la que necesitamos, iniciará una recolección de la generación 0 que consiste en limpiar los objetos que ya no use usan y subir de generación los que sí se usan.

    Después de hacer este trabajo, pueden pasar dos cosas, o ya hay memoria suficiente o no la hay. En caso de que la haya, nuestra aplicación sigue funcionando normalmente pero si no había memoria suficiente, lo que va a hacer el recolector es el mismo proceso con la generación 1. Por último, si la generación 1 tampoco es suficiente, hará lo mismo con la 2. La diferencia es que en caso de la generación 2, los objetos siguen en la generación 2.

    Vale, llegados a este punto me vas a decir: `¡¡Menuda brasa!! ¿Y esto de qué me vale?`(Con razón avise de que venían curvas). Es importante saber cómo funciona el garbage collector porque, aunque su existencia nos facilita mucho la vida, su trabajo es más prioritario que el nuestro. Esto quiere decir que cada vez que el recolector hace una recolección nuestra aplicación se va a parar mientras dure la recolección. (Por suerte esto tampoco es así al 100% pero asumamos que sí).

    Cuanto más trabaje el recolector de basura, peor rendimiento tendrá nuestra aplicación. En las mediciones del código que hemos hecho antes, solo estábamos mostrando el tiempo de ejecución, pero vamos a hacer lo mismo añadiendo la memoria:

    La imagen muestra los resultados con memoria para el código anterior donde los resultados dicen que StringConcat consume, 4921 KB StringFormat 14899 KB, StringInterpolation 492 1KB, StringAdd 4921 KB y StringBuilder solo 26 KB

    ¿Cómo reduzco el consumo de memoria de mi aplicación?

    En este punto tenemos claro que utilizar memoria de cualquier manera es algo que puede afectar negativamente al rendimiento y nosotros lo que queremos es precisamente mejorar el rendimiento de una aplicación .Net Core. Para eso .Net Core nos ofrece ciertas herramientas para poder hacer código ‘memory friendly’.

    Para esto tenemos varias opciones built-in que nos van a permitir mejorar y optimizar las reservas de memoria, consiguiendo así ponerle las cosas más fáciles al recolector.

    Devolver valores por referencia en vez de nuevas copias para mejorar el rendimiento de aplicaciones .Net Core

    Acabamos de plantear que el hecho de instanciar clases tiene un coste para el recolector de basura, pero utilizar instancias de structs tiene también su personalización. Esto es porque al ser objetos por valor, cada vez que pasemos el dato como parámetro o retorno de un método, realmente estaremos pasando una copia completa de la estructura… En este caso no son los problemas con el recolector, sino la sobrecarga de copiar datos dentro de la pila lo que pretendemos mejorar. Imagina una estructura con varios campos, el hecho de que tengamos un método que retorne una copia o una referencia puede cambiar significativamente el tiempo cuando es un código ‘caliente’ por el que se pasa miles de veces. Los resultados de llamar a este código 1000 veces ya tienen una diferencia del 30%.

    private BigStruct CreateBigStruct()
    {
        return _bigStruct;
    }
    
    private ref BigStruct CreateRefBigStruct()
    {
        return ref _bigStruct;
    }
    
    La imagen muestra los resultados de devolver una estructura por valor o por referencia, donde el hecho de devolverla por referencia mejora un 31% el tiempo usando .Net Core

    Para poder conseguir esto, lo que tenemos que hacer es hacer es añadir el ‘ref’ a la firma de nuestro método. Tras esto, después del ‘return’ también añadimos ‘ref’, para indicar que el retorno es por valor. A la hora de consumir el retorno de este método utilizaremos variables ‘ref’ locales:

    ref var item = ref CreateRefBigStruct();
    

    Vale, pero con esto estamos devolviendo una referencia y podemos modificar el contenido de la estructura… ¿Esto se puede evitar de alguna manera? Pues la respuesta es sí, gracias a las herramientas del lenguaje disponibles podemos declarar el método como ‘readonly‘. De este modo conseguimos crear una referencia de solo lectura hacia la estructura, de modo que conseguimos lo mejor de los dos mundos.

    private ref readonly BigStruct CreateRefBigStruct()
    {
        return ref _bigStruct;
    }
    ref readonly var item = ref CreateRefBigStruct();
    
    

    Span<T>/ReadOnlySpan<T>

    La primera de estas herramientas es ‘ (opens in a new tab)» href=»https://docs.microsoft.com/es-es/dotnet/api/system.span-1?view=netcore-3.1″ target=»_blank»>Span<T>‘ y su versión de solo lectura ‘ (opens in a new tab)» href=»https://docs.microsoft.com/es-es/dotnet/api/system.readonlyspan-1?view=netcore-3.1″ target=»_blank»>ReadOnlySpan<T>‘. Gracias a ella vamos a generar una referencia hacia una colección en la memoria contigua que nos va a permitir hacer operaciones sobre ella. Todo esto sin tener que generar nuevas colecciones gracias a su método Slice. Esta memoria a la que apuntamos puede estar tanto en la pila como en el montón o incluso memoria no administrada. Imaginemos esto como una ventana móvil que apunta hacia una colección completa, cuando necesitemos acceder a una parte especifica de la colección, en vez de crear una subcolección, simplemente vamos a mover la ventana a la parte que nos interesa sin crear una colección nueva.

    La imagen enseña mediante un diagrama que respecto a una colección completa, Span<T> permite abrir o cerrar la región que esta controlando mejorando así el rendimiento en .Net Core

    ‘Span<T>’ es un tipo de dato especial (ref struct) que nos garantiza que siempre se va a almacenar en la pila, por lo que solo podemos hacer uso de ella en situaciones que garanticen que esto se cumple. En caso contrario el compilador nos generará un error. Vamos a poder utilizar Span<T> como variable local, como parámetro o como retorno de un método, pero no como miembro de una clase o estructura.

    Esto es porque, aunque las estructuras en principio van a la pila, no siempre tiene porque ser así. Si por ejemplo está dentro de una clase, la estructura se almacenará en el montón.

    ¿Y qué ventajas me da esto? Pues, por ejemplo, vamos a poder crear colecciones de datos en la pila mientras que si utilizásemos una lista o array, estarían en el montón. Para poder hacer esto vamos a utilizar la palabra reservada ‘stackalloc’ para indicar que esa memoria que queremos tiene que venir de la pila.

    //Con reserva de memoria
    int[] array = new int[1024];
    //Sin reserva de memoria
    Span<int> array = stackalloc int[1024];
    

    Por poner un ejemplo, crear una colección de 100000 elementos y asignarles un valor:

    public void InitializeWithArray()
    {
        int[] array = new int[_lenght];
        for (var i = 0; i > _lenght; i++)
        {
            array[i] = i;
        }
    }
    
    public void InitializeWithStackalloc()
    {
        Span<int> array = stackalloc int[_lenght];
        for (var i = 0; i > _lenght; i++)
        {
            array[i] = i;
        }
    }
    

    Nos aporta unos resultados muy claros:

    La imagen muestra que utilizar Span consigue una reducción del tiempo de un 27% además de no consumir nada de memoria mientras que el método con array consume un total de 40 KB con lo que mejora el rendimiento en .Net Core

    El hecho de utilizar Span<T> está suponiendo un ahorro del 27% en cuanto a ejecución y además estamos evitando el uso de 40 KB de memoria del montón.

    La principal ventaja es que desde .Net Core 2.1 tiene un soporte nativo en el framework, por lo que ahora en .Net Core 3 son muchísimas las APIs del framework que nos da la opción de darle como parámetro o recibir como retorno objetos de tipo Span<T>, por lo que con unos cambios mínimos en nuestra manera de desarrollar podríamos aplicar una mejora en el rendimiento.

    Memory<T>/ReadOnlyMemory<T>

    Span<T> es muy útil como hemos visto a la hora de optimizar el uso de memoria y con ello el rendimiento en .Net Core, pero tiene sus limitaciones respecto a donde usarlo… Precisamente para suplir esas limitaciones está a nuestra disposición ‘ (opens in a new tab)» href=»https://docs.microsoft.com/es-es/dotnet/api/system.memory-1?view=netcore-3.1″ target=»_blank»>Memory‘ y su versión de solo lectura ‘ReadOnlyMemory‘. A diferencia de Span y ReadOnlySpan, estas dos nuevas versiones si pueden almacenarse en el montón y por tanto podemos usarlo en cualquier sitio.

    ArrayPool<T>

    Hasta ahora hemos planteado opciones para evitar el uso del montón para minimizar las recolecciones y evitar así tiempos muertos. Esto no siempre es posible porque la pila tiene un tamaño limitado. Si pretendemos almacenar grandes colecciones con estructuras en ella vamos a tener un desbordamiento…

    Para evitar este problema podemos aplicar una estrategia de reciclaje de memoria gracias a ‘ (opens in a new tab)» href=»https://docs.microsoft.com/es-es/dotnet/api/system.buffers.arraypool-1?view=netcore-3.1″ target=»_blank»>ArrayPool‘. Cuando una aplicación arranca, automáticamente reserva una cierta cantidad de memoria en el montón que tiene a la espera para cuando se necesite. Precisamente gracias a ArrayPool vamos a pedir prestada esa memoria del montón para hacer las operaciones y después se la devolveremos. Empleando esta estrategia vamos a conseguir que no se necesiten hacer recolecciones sobre esa memoria y vamos a mejorar el rendimiento de aplicaciones .Net Core.

    Para poder conseguir este objetivo, ArrayPool nos ofrece dos métodos con los que vamos a poder pedir y devolver memoria. Estos métodos son ‘Rent‘ y ‘Return‘.

    var array = ArrayPool<BigStruct>.Shared.Rent(1024);
    //Código que utiliza el array
    ArrayPool<BigStruct>.Shared.Return(array);
    

    Utilizando ArrayPool estamos pidiendo memoria al proceso y si no se la devolvemos, vamos a provocar una fuga de memoria que acabará en un fallo catastrófico.

    Supongamos un caso donde tengamos una colección de 1000 posiciones de una estructura grande. La diferencia entre crear un array de la manera normal o utilizar ArrayPool es esta:

    La imagen muestra que utilizar ArrayPool es más de 100 veces más eficiente además de no consumir nada de memoria

    Como se puede comprobar, utilizar ArrayPool en torno a 100 veces más eficiente. Además de la mejora de la eficiencia, también hay un ahorro de la memoria utilizada por el proceso.

    Conclusiones

    Existen más métodos de optimización para mejorar el rendimiento en aplicaciones .Net Core con lo que conseguir mejoras muy importantes aunque en esta entrada he querido plantear los más generalistas. Dicho lo anterior vuelvo a reiterar que todo esto solo se debe utilizar si se necesita y solo si se necesita. El hecho de utilizar más structs y no pensar que las clases son la solución a todo es una buena idea, al igual que utilizar las APIs con Span siempre que se pueda, pero no volverse loco sin motivo. Optimizar código suele traer consigo el dificultar la lectura respecto a código sin optimizar. Por supuesto, antes de plantearse hacer cambios como estos, siempre hay que medir. La optimización prematura es una de las mayores fuentes de problemas a la hora de desarrollar.

    ¿Conocías estas maneras de mejorar el rendimiento para .Net Core? Si crees que me he dejado algún método importante no dudes en dejarlo en los comentarios y amplio esta entrada. Todas las herramientas disponibles en el cinturón siempre son buenas. 🙂

    Para que cada uno pueda tomar sus propias conclusiones, he dejado el código en GitHub listo para poder ejecutarlo.

    **La entrada Escribiendo código de alto rendimiento en .Net Core se publicó primero en Fixed Buffer.**

    Coding Potions: Vue slots ≫ Qué son y cómo usarlos

    $
    0
    0

    Introducción ¿Qué son los slots?

    Los slots son un mecanismo de Vue JS que sirve para insertar contenido HTML dentro de los componentes. Es decir, con los props puedes pasar objetos y variables javascript a los componentes y con los slots puedes insertar contenido HTML dentro de otros componentes.

    Imagina que quieres crear un componente que sirva para renderizar un header, y además quieres que dentro del header, a la derecha se puedan poner botones o otra información de forma que cambien dependiendo de la página. Esto se puede hacer con props, pero con los slots es mucho más sencillo y encima permites que desde fuera puedes pasar el contenido HTML que quieras.

    Los slots sirven para insertar contenido en el componente hijo

    Seguramente estés confuso, pero ahora con los ejemplos lo vas a ver mucho más claro.

    Cómo crear slots en Vue

    Sigamos con el ejemplo del botón que vimos en el artículo anterior sobre props y eventos en Vue. Imagina que ahora quieres poder añadir un icono que sea personalizable para cada botón. Una forma de abordarlo es creando un prop para pasar desde fuera el nombre del icono. Otra forma de hacerlo es con slots:

    <template><button@click="handleClick"><slot></slot></button></template>
    export default {
      methods: {
        handleClick() {
          this.$emit("click", this.example);
        }
      }
    }
    <script></script>

    El slot es una etiqueta especial que tiene Vue. Cuando pones un slot lo que estás diciendo es que en ese punto vas a colocar contenido desde fuera. Fíjate que ahora no necesitamos poner un prop, porque todo el contenido que vaya dentro del botón se pasará desde fuera.

    Veamos ahora cómo pasar contenido a los slots:

    <template><my-button@click="handleClick"><iclass="fas fa-cat"></i>
        Botón de ejemplo
      </my-button></template>
    
    import MyButton from "@/components/MyButton.vue";
    
    export default {
      components: {
        MyButton
      },
      methods: {
        handleClick(info) {
          console.log("Click event on the button of the children with: " + info)
        }
      }
    }
    <script></script>

    Todo el contenido que pongas dentro de la etiqueta HTML de un componente con slot se sustituirá dentro del componente en el lugar en el que esté colocada la etiqueta slot. Para el ejemplo anterior, el botón finalmente quedará como:

    <button><iclass="fas fa-cat"></i>
      Botón de ejemplo
    </button>

    Pero no todo es bueno con los slots. La parte mala de los slots es que das demasiada libertad a la hora de usar el componente. Por ejemplo para el caso del botón, alguien podría poner dentro del slot una tabla por ejemplo haciendo que el botón se vea mal. Para este caso en concreto yo usaría un prop para el texto del botón y otro prop para el icono.

    Más de un slot. Named slots

    Otra cosa que se puede hacer con Vue es añadir más de un slot, para ello vas a tener que colocar un nombre a cada slot para poder indentificarlos:

    <divclass="container"><header><slotname="header"></slot></header><main><slot></slot></main><footer><slotname="footer"></slot></footer></div>

    Con el atributo name le pones el nombre a cada slot. Para poder elegir qué poner en cada slot tienes que usar una etiqueta de Vue llamada template.

    Los templates son unas etiquetas especiales de Vue que cuando se compila la página se eliminan dejando solo su contenido. En el ejemplo de abajo se colocará el contenido definido para cada slot en su sitio del componente eliminándose las etiquetas template y solo quedando los headings y los párrafos

    <base-layout><templateslot="header"><h1>Header de la página</h1></template><p>Contenido de la página</p><templateslot="footer"><p>Footer de la página</p></template></base-layout>

    El ejemplo de arriba finalmente quedará renderizado como:

    <divclass="container"><header><h1>Header de la página</h1></header><main><p>Contenido de la página</p></main><footer><p>Footer de la página</p></footer></div>

    Las etiquetas template han desaparecido. El slot del medio, el del contenido, no tiene nombre y por lo tanto será sustituido en el slot por defecto sin nombre.

    Contenido por defecto del slot

    También puedes poner contenido por defecto en caso de que no uses el slot:

    <buttontype="submit"><slot>Submit</slot></button>

    En caso de que al crear este componente botón no le pases contenido, Vue lo creará con el texto Sumbit.

    Con esto puedes crear todo el contenido que quieras dentro de los slots por si al usar el componente no pasas nada dentro.

    Scoped slots

    Los scoped slots es de esas cosas que no los conoce mucha gente. Lo que permiten los scoped slots es poder pasar información desde el componente hijo al padre, es decir, desde el hijo pasas contenido al padre para que éste lo pueda pintar como necesite.

    Ponte en el ejemplo de que tienes un componente que pinta una lista de usuarios. A este componente le pasas un prop con el array de usuarios a pintar. Pues bien, con los scoped slots, al hacer el v-for para pintar los usuarios, puedes pasar al componente padre, en el slot, el usuario que se está pintando en ese momento de tal forma de que en el padre decides cómo lo quieres pintar. Por ejemplo:

    En el componente hijo:

    <ul><liv-for="(user, i) in users":key="i"><slotv-bind:user="user"></slot></li></ul>

    Dentro del slot haces bind de la variable user que se está pintando para pasarla al componente padre.

    En el componente padre:

    <user-list><templatev-slot:default="slotProps"><span>{{ slotProps.user.firstName }}</span><span>{{ slotProps.user.lastName }}</span></template></user-list>

    Recoges la variable del user en slotProps y pintas el usuario como necesites.

    Por ejemplo, usando el mismo componente, también podrías tener a la vez en otro componente:

    <user-list><templatev-slot:default="slotProps"><div>First name: </div><div>{{ slotProps.user.firstName }}</div><div>Last name: </div><div>{{ slotProps.user.lastName }}</div></template></user-list>

    Esto es muy útil cuando quieres tener un componente de tabla o un componente que pinte una lista o colección de elementos y necesitas dos formas diferentes de pintarlos. Recogiendo el valor en los componentes padres puedes decidir cómo vas a querer renderizarlo usando un solo componente hijo.

    Conslusiones

    Como he dicho, yo personalmente recomiendo crear los componentes usando props y no slots porque así limitas más el contenido de los componentes para que no queden cosas extrañas. De todas formas para ciertos componentes sobre todo estructurales en los que necesitas pasar mucho contenido HTML su uso si que está más justificado.

    En próximos capítulos veremos como estructurar los proyectos de Vue para poder mandar peticiones HTTP a un servidor o API y así poder conectar a las aplicaciones creadas en Vue con un servidor con bases de datos.

    Navegapolis: Por qué pusimos en marcha un registro de propiedad intelectual

    $
    0
    0

    safe creative cc tech summit

    En 2007, cuando pusimos en marcha Safe Creative, muchos expertos dudaban si era posible abrir en internet un registro de propiedad intelectual.

    El mismo Creative Commos nos invitó en el  Technology Summit de 2008,  a explicar "por qué y para qué un registro de propiedad intelectual", presentándonos con un título que parecía cuestionarlo: "Developers of digital copyright registries and similar animals" :-P 

    ¿Por qué un registro electrónico? ¿Por qué no seguir registrando como siempre en oficinas de registro de ministerios o consejerías de educación?

    Los registros de propiedad intelectual no otorgan derechos: el autor de una obra creativa tiene todos sin necesidad de registrarlos (Convenio de Berna). Lo que ocurre es que resulta muy aconsejable que registre su obra antes de "moverla", para tener asentada una primera prueba declarativa de su autoría, para publicar su trabajo o enviar versiones previas con tranquilidad, sabiendo que dispone de la merjor prueba en el tiempo frente a quien pudiera estar tentado de atribuírselo.

    Y así fue. Para subir a internet la canción que hemos compuesto, el vídeo, el libro.... con la seguridad de haberlo registrado previamente, sin tener que esperar a que abra la ventanilla del registro a las 9 de la mañaña para llevarles  una copia. Para eso nació Safe Creative (y para otras muchas cosas que tampoco se pueden hacer en un registro tradicional).

    ... que preguntárselo hace 13 años era normal, ¡pero a estas alturas!     ;-)

     

     EN EL REGISTRO TRADICIONALEN SAFE CREATIVE
       
    La prueba de derechos de autoría se basaEs la presunción administrativa de veracidad que la ley del país correspondiente concede al funcionario que inscribe la manifestación del autor.Es una evidencia tecnológica que constituye la identificación de la obra con 3 huellas criptográficas diferentes, y de la fecha por la aplicación de un sellado de tiempo cualificado, redundado con un proceso de auditoría diaria sobre blockchain. 
       
    Validez internacionalLa presunción de veracidad es válida en su propio país.La peritación de pruebas o evidencias tecnológicas es válida en todas las jurisdicciones,
       
    OperativaNormalmente presencial, con formatos de obras en algunos casos definidos y restringidos por reglamentos internos.

    On line 24 x 7 en cualquier formato que permita identificar a la obra.

     


    Blog Bitix: El recolector de basura de Java, que hace y como funciona en cada versión

    $
    0
    0

    El recolector de basura o garbage collector es una de las piezas fundamentales del lenguaje Java y su plataforma. Una ventaja sobre lenguajes que no poseen reflectores de basura y que se ha adoptado por los lenguajes desarrollados en la últimas décadas. Facilita a los programadores la creación de programas, una mayor productividad, evita errores y fallos de seguridad.

    Java

    Den entre las características de Java ¿a qué se debe su popularidad? ¿al lenguaje simple de fácil lectura sin crípticas expresiones? ¿a ser multiplataforma, write once, run everywhere? ¿a la máquina virtual JVM que lo hace independiente de la plataforma sistema operativo y soporta múltiples lenguajes compilados a bytecode? ¿a su extensa y completa documentación Javadoc de cada clase incluida en el JDK? ¿a las clases incluidas en el JDK con una completa librería para trabajar con colecciones, interfaces gráficas o conexión a bases de datos? ¿a mantener la compatibilidad hacia atrás de modo que programas escritos hace 20 años sigan compilando y funcionando en versiones más recientes de la máquina virtual?

    Además de todas las anteriores entre las principales hay que añadir la recolección de basura que libera al programador la gestión de la memoria, tanto para solicitarla como para devolverla al sistema. Lenguajes más antiguos y con otros propósitos más cercanos a la programación de sistema donde prima el rendimiento y el acceso cercano al hardware como C no poseen recolector de memoria y requieren que el programador solicite de forma explícita con la función malloc la memoria y el tamaño de la memoria a reservar y la libere también cuando se deja de usar de forma explícita con la llamada a la función free.

    Esto para cada dato y en un programa grande serán muchos supone una dificultad añadida a la creación y mantenimiento. Este ejemplo en código C muestra el uso de la función malloc con la que el programa solicita memoria al sistema operativo y con free la libera.

     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
    
    #include<stdio.h>#include<stdlib.h>intmain(){    int*ptr;    // allocate memory
        ptr=(int*)malloc(1*sizeof(int));    // if memory cannot be allocated
        if(ptr==NULL)    {        printf("Error! memory not allocated.");        exit(0);    }    printf("Enter a number: ");    scanf("%d",ptr);    // print the number
        printf("Number = %d\n",*ptr);    
        // deallocating the memory
        free(ptr);    return0;}
    main.c
    1
    2
    3
    4
    5
    
    [picodotdev@archlinux ~]$ gcc main.c -o main
    [picodotdev@archlinux ~]$ ./main
    Enter a number: 7
    Number = 7
    [picodotdev@archlinux ~]$
    main.out

    Como desarrollador de Java apenas hay que preocuparse de fugas de memoria ni de fallos en el programa por liberar memoria antes de que dejar de usarla. En Java la solicitud de memoria al sistema se hace de forma explícita con la palabra reservada new para crear una instancia de un objeto pero no hace falta especificar el tamaño de la memoria a reservar como en C. Tampoco hace falta liberar de forma explícita el objeto cuando dejar de usarse es el propio recolector de basura el que determina si una instancia ha quedado inaccesible desde el programa y lo libera en el proceso de recolección de basura que ejecuta la máquina virtual de forma periódica y automática sin la intervención del programa.

    El recolector de basura además de simplificar el código de las aplicaciones, evita fallos en tiempo de ejecución con posibilidad de que sean difíciles de depurar, evita en gran medida las fugas de memoria y fallos graves de seguridad. En los programas en C es muy común errores de seguridad por casos en los que se sobreescriben zonas de memoria contiguas por no hacer comprobaciones en los límites de los arrays, muchos boletines de seguridad CVE en muchas librerías tienen un origen de este tipo. En Java si se intenta acceder a un array fuera de sus límites se produce una excepción ArrayIndexOutOfBoundsException, el programa sigue teniendo un error pero no tiene por que terminar su funcionamiento de forma drástica porque el sistema operativo lo mata y no son posibles los fallos de seguridad por sobreescribir una zona de memoria contigua al array pero fuera de sus límites.

    La desventaja de los recolectores de basura es que cada cierto tiempo requieren detener la ejecución de la aplicación para proceder a liberar la memoria dejada de usar por la aplicación. Estas pausas que suceden fuera del control de la aplicación hace que para entornos donde se necesite una respuesta bajo unos términos de tiempo bajos o extremadamente alto rendimiento como en el caso de sistemas en tiempo real hace que los recolectores de basura sean una dificultad.

    En Java una de las áreas para mejorar el rendimiento y tiempo de respuesta de las aplicaciones es modificar el algoritmo de recolección de basura, para mejorar el tiempo que necesita para ejecutarse y número de pausas además de posibilitar el paralelizar la ejecución del recolector de basura con la ejecución de la aplicación. A lo largo de los años en Java ha habido varios recolectores de basura.

    Salvo casos en los que hay que ajustar al límite la máquina virtual en aplicaciones que necesitan gran rendimiento no es necesario preocuparse por el funcionamiento del recolector de basura, hace su cometido como se espera. En mis años de experiencia nunca he tenido que configurarlo, pero es interesante conocer que mejoras se van implementando en cada nueva generación de algoritmo. En la mayoría de los casos parece que el sucesor se basa en el anterior y aporta alguna mejora.

    En la revista JavaMagazine se han publicado varios artículos explicando el recolector de basura de Java. En las secciones de las diferentes versiones de recolectores de basura resumo parte del contenido de esos artículos.

    Otros artículos relativos a la recolección de basura y su configuración son los de la Garbage Collection Tuning con una explicación más detallada.

    Cómo funciona el recolector de basura

    En un lenguaje orientado a objetos como Java los datos están contenidos en los objetos. Los objetos son almacenados en el espacio de memoria del sistema denominado heap distinta a la memoria del código ejecutable del programa, datos para las constantes y de las pilas de memoria para los argumentos y valores de retorno entre métodos.

    Las clases de colecciones de Java contienen referencias a objetos. Un ejemplo podría ser el siguiente de un árbol binario.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    classTreeNode{    privateTreeNodeleft;    privateTreeNoderight;    privateintdata;    TreeNode(TreeNodel,TreeNoder,intd){        this.left=l;        this.right=r;        this.data=d;    }    publicvoidsetLeft(TreeNodel){        left=l;    }    publicvoidsetRight(TreeNoder){        right=r;    }}
    TreeNode.java

    Al insertar nodos todos los objetos insertados están accesibles.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    ...publicclassMain{    publicstaticvoidmain(String[]args){        TreeNodeleft=newTreeNode(null,null,13);        TreeNoderight=newTreeNode(null,null,19);        TreeNoderoot=newTreeNode(left,right,17);        ...        root.setRight(newTreeNode(null,null,21));    }}
    Main.java

    Objetos al inicializar la estructura de datos

    Objetos al inicializar la estructura de datos

    Al realizar la operación de eliminación de un nodo del árbol el objeto eliminado del árbol deja de ser accesibles para el programa sino hay más referencias en otras estructuras de datos con la que alcanzar a ese objeto y pasa a ser reclamable por el recolector de basura.

    Objetos después de eliminar un nodo

    Objetos después de eliminar un nodo

    Con más operaciones los objetos no accesibles aumentan. Estos objetos no accesibles siguen consumiendo memoria, el recolector de basura se encarga de liberar la memoria de esos objetos y después compactar la memoria en uso y la liberada queda utilizable para nuevas instancias de objetos.

    Objetos después de realizar múltiples operaciones de inserción

    Objetos después de realizar múltiples operaciones de inserción

    Al realizar la operación de compactar la memoria los objetos cambian de ubicación y el programa debe conocer la nueva ubicación, esto requiere actualizar las referencias de los objetos almacenados en las estructuras de datos. La forma fácil de realizar la liberación de memoria y la compactación es parar los threads de la aplicación, liberar la memoria, compactarla y actualizar todas las referencias de los objetos a la nueva ubicación, después reiniciar la aplicación. Esta parada de la aplicación se conoce como stop-the-world. Sin embargo, el parar la aplicación reduce el rendimiento, esto no es deseable.

    Para reducir las pausas de los recolectores de basura hay dos estrategias:

    • Los algoritmos concurrentes: realizar el trabajo mientras funciona la aplicación, la aplicación no necesita pausas ni sufre pérdida de rendimiento.
    • Los algoritmos paralelos: emplear más threads para hacer el trabajo más rápido, aumenta el rendimiento del recolector de basura.

    El recolector de basura por defecto en Java 8 usar la estrategia paralela, usa varios threads para tener un alto rendimiento. Otras versiones de algoritmos emplean ambas técnicas simultáneamente para tener un alto rendimiento y apenas sin pausas. Hay dos áreas de mejora en los algoritmos de recolección de basura y medir su desempeño. La primera es el rendimiento, cuanta cantidad de tiempo de CPU de la aplicación es gastada en realizar recolección de basura en vez de ejecutar código de la aplicación. La segunda es el tiempo de latencia en las pausas.

    Recolector de basura Parallel

    El recolector de basura parallel emplea zonas para segregar los objetos, la zona de objetos jóvenes y la zona de objetos viejos. Inicialmente los objetos se crean en la zona de objetos jóvenes, cuando han sobrevivido a varios ciclos del recolector de basura son movidos a la zona de objetos viejos.

    La razón es que en vez de recolectar los objetos de toda la memoria hay más probabilidad de recolectar más objetos que han dejado de usarse en la zona de objetos jóvenes. Eventualmente también es necesario recolectar los objetos de la zona de objetos viejos.

    Es el recolector de basura por defecto en Java 8 y anteriores. La opción para usar este recolector de basura es la siguiente.

    1
    
    -XX:+UseParallelGC
    java-option-gc-parallel.txt

    Recolector de basura Garbage First o G1

    El recolector de basura G1 usa ambas estrategias la paralela y la concurrente. Usa threads concurrentes mientras la aplicación está funcionando buscando los objetos vivos y usa la estrategia paralela para realizar la recolección y compactación rápidamente manteniendo las pausas bajas.

    El recolector de basura G1 también divide la memoria en regiones de memoria catalogadas como de objetos jóvenes y objetos viejos. Las regiones de objetos jóvenes las recolecta en cada pausa, para las zonas de objetos viejos tiene cierta flexibilidad para recolectar muchas o pocas como la estimación de tiempo que le llevará hacerlo le permita para cumplir con el objetivo de tiempo de pausa configurado dado que permite ajustar según preferencia el límite de tiempo máximo deseado para las pausas.

    División por zonas de G1 y compactación de objetos

    División por zonas de G1 y compactación de objetos

    G1 conoce cuantos datos vivos hay en cada región, lo calcula con la estrategia concurrente mientras la aplicación está funcionando, y el tiempo aproximado que consume copiar los datos vivos. Si se prefieren pausas bajas por el tiempo de pausa configurado G1 puede elegir evacuar solo unas pocas regiones. Si las pausas pueden ser mayores G1 puede elegir mayor número de regiones. Esta flexibilidad le permite a G1 liberar primero las zonas de objetos viejos en las que estime que liberará más objetos dado que conoce cuantos objetos siguen vivos.

    La contrapartida de especificar pausas bajas es que G1 puede no ser capaz de mantener el ritmo de liberación de memoria, en cuyo caso eventualmente opta por parar la aplicación con el modo stop-the-world. Esto implica que el proceso de búsqueda de objetos vivos y el proceso de copiado es realizando mientras los threads de la aplicación están parados. Si G1 no puede cumplir con el objetivo de tiempo de pausa en recolecciones parciales, entonces el recolector de basura necesitará una pausa de mayor tiempo que el límite máximo deseado especificado.

    G1 en general es un recolector con un buen balance entre rendimiento y restricciones de tiempo de pausa. Es el recolector de basura por defecto en Java 9.

    1
    
    -XX:+UseG1GC -XX:MaxGCPauseMillis=200
    java-option-gc-g1.txt

    Recolector de basura Shenandoah

    Usa la misma disposición de regiones que G1 y usa el mismo sistema de escaneo concurrente para calcular la cantidad de objetos vivos en cada región. Difiere en que la compactación también es concurrente, de modo que no necesita limitar el número de regiones a recolectar para minimizar los tiempos de las pausas.

    La dificultad para Shenandoah es que la copia concurrente se realiza al mismo tiempo que los threads de la aplicación están accediendo al objeto de modo que ambos deben estar de acuerdo en donde está el objeto. La dirección del objeto puede estar en otros varios objetos y la actualización debe realizarse simultáneamente.

    La solución que aplica es una indirección. Los objetos son reservados en memoria con espacio extra para un puntero de indirección. Cuando los threads de Java acceden al objeto leen primero el puntero de indirección para ver donde se ha movido el objeto. Cuando el recolector de basura mueve el objeto, actualiza el puntero de indirección a la nueva localización. Los objetos nuevos tienen un puntero de indirección que apunta a si mismos. Solo cuando el objeto es copiado durante la recolección de basura el puntero de indirección apunta otro sitio. Si el programa Java modifica los datos de un objeto que Shenandoah está copiando, se produce un problema de concurrencia que es solventado haciendo que los threads de la aplicación cooperen con los threads del recolector de basura.

    Shenandoah elimina la necesidad de realizar pausas durante la compactación de modo que las pausas cuando se hacen son mucho menores. El recolector de basura Shenandoah es un proyecto de OpenJDK que forma parte del OpenJDK 12 y está siendo portado al JDK 8 y 11. Se puede activar en Java 12 con la siguiente opción de la máquina virtual.

    1
    
    -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
    java-option-gc-shenandoah.txt

    Recolector de basura ZGC

    Para los algoritmos que realizan pausas incrementar la memoria heap mejora el rendimiento dado que el número de pausas es menor por la menor necesidad de liberar memoria pero hace que las pausas sean más largas porque hay más trabajo que realizar dado que la memoria total es mayor.

    Los objetivos principales de ZGC son baja latencia, escalabilidad y facilidad de uso. Para conseguirlo todas las operaciones de recolección de basura se realizan de forma concurrente mientras la aplicación continúa ejecutándose salvo algunas excepciones. Escala desde unos cientos de megabytes de memoria a memorias de tamaño de terabytes manteniendo consistentemente tiempos bajos de pausas menores de entre 10 y 2 ms.

    Los recolectores de basura anteriores y hasta ahora necesitaban realizar pausas stop-the-world para algunas operaciones de recolección de basura. Para un recolector de basura de baja latencia esto es problemático de modo que ZGC realiza todas las operaciones concurrentemente a la aplicación de modo que no hay apenas latencias.

    Comparación de latencia entre ZGC, Parallel y G1

    Comparación de latencia entre ZGC, Parallel y G1

    ZGC se puede activar en Java 13 con la siguiente opción para la máquina virtual.

    1
    
    -XX:+UnlockExperimentalVMOptions -XX:+UseZGC
    java-option-gc-zgc.txt

    Blog Bitix: Las aplicaciones integradas del entorno de escritorio GNOME

    $
    0
    0

    Todos los entornos de escritorio poseen unas pocas aplicaciones básicas y sencillas pero de uso muy común para todos los usuarios. Estas aplicaciones del entorno de escritorio están estrechamente integradas para ofrecer una experiencia de usuario consistente y funcionar correctamente entre ellas. GNOME posee varias desde un editor de archivos de texto, una calculadora, captura de pantalla, visor de imágenes, reproductor de música y vídeo, gestor de correo electrónico, calendario, navegador web, juegos, … y otras más.

    GNOME

    Todos los equipos informáticos incorporan un sistema operativo, este es una pieza importante e indispensable de software que abstrae las las especificidades de cada elemento hardware además de permitir se uso compartido desde la CPU, memoria, almacenamiento persistente, comunicación de red entre otros muchos componentes y periféricos que poseen los ordenadores actuales. Pero simplemente ofrece una interfaz de bajo nivel destinada a los programas no el usuario.

    Para facilitar el uso el sistema operativo y en los actuales ofrecer una interfaz gráfica a través de ventanas, imágenes y texto a los usuarios están los entornos de escritorio. Los entornos de escritorio además incorporan una colección de aplicaciones de uso común para todos los usuarios como un navegador de archivos, navegador web, editor de texto, reproductor de música, reproductor de vídeo, visor de imágenes y documentos, gestor de aplicaciones, calculadora, capturador de pantalla entre las básicas.

    Capas de software desde el hardware hasta el entorno de escritorio

    Capas de software desde el hardware hasta el entorno de escritorio

    Ejemplos de sistema operativos son GNU/Linux, Windows, macOS o FreeBSD. En los casos de Windows y macOS el mismo nombre engloba la interfaz gráfica y el entorno de escritorio sin ofrecer ninguna alternativa, en GNU/Linux hay varias alternativas de entorno de escritorio a elegir según las preferencias del usuario entre ellas GNOME, KDE, XFCE, Pantheon de elementary OS, MATE, Cinnamon o LXDE.

    Las distribuciones de GNU/Linux proporcionan el conjunto de software completo formado por el núcleo o kernel que con el conjunto de aplicaciones de GNU forman el sistema operativo, el entorno de escritorio con sus aplicaciones básicas y finalmente aplicaciones adicionales que no forman parte del entorno de escritorio pero son preinstaladas en la instalación del sistema. Algunos ejemplos de distribuciones GNU/Linux son Ubuntu, Fedora, openSUSE, Debian, Arch Linux o elementary OS entre muchas otras.

    UbuntuopenSUSEDebian

    Arch LinuxFedoraElementary OS

    El entorno de escritorio se instala con el sistema con lo que primero es elegir una distribución GNU/Linux, para los usuarios que proviene de Windows o macOS y quieren probar GNU/Linux una distribución recomendable es Ubuntu. El siguiente paso seguir la guía de como instalar Ubuntu paso a paso desde cero y conocer las tareas básicas de administración y uso después de instalar una distribución. Para los usuarios que ya conocen GNU/Linux, quieren personalizar el sistema con sus preferencias no las de los desarrolladores de la distribución y prefieren un modelo de ciclo de vida rolling release en el que el software se mantiene en constante actualización con las últimas versiones puede instalar Arch Linux de forma rápida, desatendida y personalizable con un scipt.

    El entorno de escritorio GNOME

    GNOME con las críticas iniciales a la versión primera de la rama 3.0 publicada en abril del 2011 por el cambio significativo respecto a versiones anteriores ha mejorado mucho y sigue haciéndolo con cada nueva versión publicada cada seis meses.

    En GNOME se opta por la simplicidad, a veces criticada por la falta de opciones de configuración y personalización, en la que los detalles gráficos y la usabilidad del sistema son aspectos con más relevancia respecto a versiones anteriores.

    Continúan realizándose mejoras, algunas de las cuales son aplicadas en cada nueva versión y otras registradas para tenerlas en cuenta en futuras versiones.

    Escritorio de GNOMELanzador de aplicaciones de GNOMELanzador de aplicaciones de GNOME

    Entorno de escritorio y lanzador de aplicaciones de GNOME

    Aplicaciones del entorno de escritorio GNOME

    GNOME integra un conjunto de aplicaciones que proporcionan una funcionalidad importante en la experiencia del entorno de escritorio.

    Estas aplicaciones están diseñadas por los propios diseñadores de GNOME como un paquete coherente, son parte de la experiencia GNOME, están diseñadas para funcionar de forma cooperativa unas con otras, tienen una integración fuerte con el entorno de escritorio, tienen nombres genéricos y son exclusivas de la experiencia GNOME.

    El conjunto de aplicaciones del núcleo o esenciales de GNOME está formado por unas 30 agrupadas en diferentes categorías.

    Conversaciones y organización personal

    • Evolution: cliente de correo electrónico y organizador
    • Geary: cliente de correo electrónico
    • Contactos
    • Calendario

    EvolutionGeary

    ContactosCalendarioCalendario

    Archivos

    • Visor de imágenes
    • Fotos
    • Documentos
    • Gestor de archivos (compresor)
    • Música
    • Lollypop: reproductor de música
    • Vídeos

    Visor de imágenesFotosFotos

    DocumentosArchivos

    MúsicaMúsicaMúsica

    Lollypop

    VídeosVídeosVídeos

    Herramientas de sistema

    • Captura de pantalla
    • Discos
    • Ayuda
    • Trazas
    • Informar de problema
    • Terminal
    • Uso (system monitor + disk usage)

    Captura de pantallaDiscosAyuda de GNOME

    TerminalTerminalMonitor del sistema

    Sistema esencial

    • Configuración: opciones de configuración del sistema
    • Software: instalar, actualizar y desinstalar programas de software
    • Web: navegador de páginas web

    ConfiguraciónConfiguraciónConfiguración

    SoftwareSoftware

    WebWebWeb

    Mundo

    • Relojes
    • Tiempo
    • Mapas

    RelojesTiempo

    MapasMapasMapas

    Mapas

    Utilidades

    • Calculadora
    • Tipografías
    • Notas
    • Editor de texto
    • Retoques: ofrece varios opciones de personalización
    • Herramientas de red

    CalculadoraCalculadora

    TipografiasTipografias

    NotasEditor de textoRetoques

    Herramientas de red

    Propósito especial

    • Cajas: virtualización

    CajasCajasCajas

    Audio y vídeo

    • Cheese: aplicación webcam
    • Sound Juicer: extractor de CD de audio
    • Grabadora de sonido

    CheeseGrabadora de sonido

    Creación y edición

    • Brasero: grabadora de CD y DVD
    • EasyTAG: editor de metadados de archivos de música
    • Subtítulos: editor de subtítulos para archivos de vídeo

    Comunicación

    • Fractal
    • Polari

    Entornos de desarrollo

    • Builder: entorno integrador de desarrollo
    • Glade: diseñador de interfaces gráficas de GNOME

    BuilderBuilderBuilder

    BuilderGladeGlade

    Juegos

    Aventura
    • MUD
    • Arcade
    • Nibbles
    • Robots
    • Blocks
    • Quadrapassel (Lines)
    • Board
    • Chess
    • Iagno
    • Mahjongg
    Cartas
    • Aisleriot (Solitaire, sol)
    • Tali
    Emuladores
    • Juegos: emulador de juegos
    Lógica
    • 2048
    • Atomix
    • Five or more
    • Four in a row
    • gbrainy
    • Hitori
    • Klotski
    • Lights off
    • Mines
    • Sudoku
    • Swell Foop
    • Taquin
    • Tetravex

    Juegos

    AjedrezKlotskiMinas

    SudokuSwell FoopTetravex

    Formatos de vídeo y audio y aplicaciones de terceros

    Para que las aplicaciones de vídeos y música soporten más formatos de archivo es necesario instalar los decodificadores de esos formatos. En Arch Linux los siguientes paquetes.

    Códecs no encontrados en Vídeos

    1
    
    $ sudo pacman -S gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav
    pacman-gstreamer.sh

    Las aplicaciones de terceros proporcionan funcionalidades adicionales, son una alternativa a las de GNOME con más funcionalidades o complementan a estas que algunos usuarios necesitan como paquete ofimático con procesador de documentos, hoja de cálculo y presentaciones, edición de vídeo, editor de fotos, editor de imágenes vectoriales, editor de animación 3D, gestor de biblioteca de libros electrónicos, descargas de archivos, mensajería instantánea, videoconferencia, nube privada, otro reproductor de audio y vídeo, conversores entre formatos de audio y vídeo, compiladores, bases de datos, gestor de contraseñas, …

    En otro artículo recojo un listado de programas básicos según categoría en GNU/Linux de terceros que no son específicos de ningún entorno de escritorio. Todos esos programas son software libre sin coste de licencia de uso para cualquier propósito incluyendo que sea personal o empresarial con fines lucrativos.

    Variable not found: Enlaces interesante 391

    $
    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 / Mobile

    Otros

    Publicado en Variable not found.

    Variable not found: Rutado dinámico en ASP.NET Core 3 MVC

    $
    0
    0
    ASP.NET Core MVCEn muchas ocasiones, la llegada de una nueva versión de un framework viene acompañada de documentación, posts y otro tipo de contenidos que anuncian a bombo y platillo las principales novedades y cambios introducidos. Ante este ruido, es fácil pasar por alto otros pequeños cambios que introducen mejoras a los marcos de trabajo o simplemente permiten ir evolucionando código antiguo a funcionalidades más recientes.

    Hoy vamos a hablar de una de eso pequeños descubrimientos: el rutado dinámico de controladores. Introducido en ASP.NET Core 3, se trata de una característica que no ha sido especialmente publicitada ni comentada, pero puede ser de utilidad en algunas ocasiones, pues permite interferir en la forma de interpretar las rutas de las peticiones entrantes con objeto de decidir en cada caso cómo deben ser procesadas.

    Rutado estático vs rutado dinámico

    Seguro que muchos estáis ya empezando a utilizar el flamante endpoint routing para definir las rutas hacia controladores o páginas Razor de vuestras aplicaciones y reconoceréis el siguiente código, perteneciente al método Configure() de la clase Startup, que configura las rutas por defecto para los controladores MVC de una aplicación:
    app.UseEndpoints(endpoints =>
    {
    endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
    });
    En esta definición estamos estableciendo una férrea relación entre un patrón de ruta y la ubicación de los endpoints que procesarán las peticiones que encajen con el mismo. Estas definiciones, grabadas a fuego durante el arranque de la aplicación, dan poco margen para la sorpresa: por ejemplo, una petición hacia "/products/show" será procesada desde la acción "Show" del controlador "Products" inexorablemente.

    Sin embargo, hay escenarios en los que necesitamos más flexibilidad y queremos ser nosotros los que seleccionemos el controlador y acción que procesará una petición, manipular los parámetros de ruta existentes o incluso añadir parámetros de ruta personalizados. Estas posibilidades son las que se abren con el rutado dinámico de ASP.NET Core 3.
    Algunos probablemente habréis hecho este tipo de cosas mediante implementaciones personalizadas de IRouter: tened en cuenta este mecanismo ya no es compatible con endpoint routing y habría que migrarlo a este nuevo enfoque.

    Transformaciones de valores de ruta

    En la práctica, el rutado dinámico se implementa en clases transformadoras de valores de ruta, componentes personalizados que serán invocados en cada petición para darles la oportunidad de modificar a su antojo los parámetros de ruta.

    Estas clases transformadoras deben heredar de DynamicRouteValueTransformer, una abstracción proporcionada por el framework que tiene la siguiente pinta:
    public abstract class DynamicRouteValueTransformer
    {
    public abstract ValueTask<RouteValueDictionary> TransformAsync(
    HttpContext httpContext,
    RouteValueDictionary values);
    }
    Cuando heredemos de ella para crear nuestra transformación personalizada, el método TransformAsync() recibirá el objeto HttpContext y los valores de parámetros de ruta que han sido detectados hasta este momento en forma de diccionario. El objetivo de las transformaciones que implementaremos en la clase es alterar el contenido del diccionario de parámetros de ruta para que el comportamiento se adapte a nuestras necesidades, por ejemplo:
    • Si quisiéramos modificar la acción o controlador que procesaría una petición, sólo tendríamos que alterar el valor de los parámetros de ruta action o controller.
    • Podríamos añadir nuevos parámetros de ruta en función de los datos de entrada.
    • Podríamos reemplazar valores por otros, por ejemplo para traducirlo a una cultura neutra, des-sluggizarlo o transformarlo de alguna forma.
    Una vez realizadas las modificaciones que consideremos sobre el diccionario de rutas, simplemente retornaremos una referencia hacia el mismo. Por tanto, el esquema de una implementación personalizada de DynamicRouteValueTransformer podría ser como el siguiente:
    public class MyCustomTransformer : DynamicRouteValueTransformer
    {
    public override async ValueTask<RouteValueDictionary> TransformAsync(
    HttpContext httpContext, RouteValueDictionary values)
    {
    // Modificamos la colección de parámetros de ruta, por ejemplo:
    // values["controller"]="Products"
    return values;
    }
    }
    Para que una clase transformadora pueda ser utilizada, debemos registrarla previamente en el método ConfigureServices(). Podemos utilizar cualquier tipo de lifetime, por lo que somos libres de elegir el que más convenga:
    public void ConfigureServices(IServiceCollection services)
    {
    ...
    services.AddScoped<MyCustomTransformer>();
    }
    Fijaos que lo interesante de esto es que, dado que sus instancias son suministradas por el proveedor de servicios, podríamos utilizar inyección de dependencias en su constructor, :
    public class MyCustomTransformer : DynamicRouteValueTransformer
    {
    private readonly IMyService _service;
    public LocalizationTransformer(IMyService service)
    {
    _service = service;
    }
    public override ValueTask<RouteValueDictionary> TransformAsync(
    HttpContext httpContext, RouteValueDictionary values)
    {
    // Usamos "service" para alterar los parámetros de ruta
    }
    }
    Además, a la hora de registrar los endpoints tendremos que usar el extensor MapDynamicControllerRoute, indicar la clase DynamicRouteValueTransformer donde hemos implementado la lógica de transformación, y especificar el patrón de ruta:
    app.UseEndpoints(endpoints =>
    {
    endpoints.MapDynamicControllerRoute<MyRouteTransformer>(
    "{controller=Home}/{action=Index}/{id?}");
    });
    Nota: de la misma forma, podemos utilizar MapDynamicPageRoute() si lo que queremos es intervenir en las peticiones dirigidas a páginas Razor.

    Ejemplo 1: localización simple de rutas

    Veamos un ejemplo de DynamicRouteValueTransformer que implementa una sencilla transformación para traducir el controlador y acción a un idioma neutro, de forma que peticiones como "/products/view" o "/productos/ver" puedan ser procesadas desde ProductsController.View():
    public class LocalizationTransformer : DynamicRouteValueTransformer
    {
    public override ValueTask<RouteValueDictionary> TransformAsync(
    HttpContext httpContext, RouteValueDictionary values)
    {
    var controllerName = (string)values["controller"];
    if ("productos".Equals(controllerName, StringComparison.InvariantCultureIgnoreCase))
    {
    values["controller"] = "products";
    }
    var actionName = (string)values["action"];
    if ("ver".Equals(actionName, StringComparison.InvariantCultureIgnoreCase))
    {
    values["action"] = "view";
    }
    return new ValueTask<RouteValueDictionary>(values);
    }
    }
    Aunque el ejemplo anterior es bastante simple porque está todo hardcodeado, obviamente podríamos crear soluciones bastante más potentes si tenemos en cuenta que la clase podría recibir dependencias y que en el método TransformAsync() tenemos toda la información del contexto disponible:
    public class LocalizationTransformer : DynamicRouteValueTransformer
    {
    private readonly ILocalizationServices _loc;
    public LocalizationTransformer(ILocalizationServices loc)
    {
    _loc = loc;
    }
    public override ValueTask<RouteValueDictionary> TransformAsync(
    HttpContext httpContext, RouteValueDictionary values)
    {
    // Usar _loc para acceder a las traducciones:
    // values["controller"] = await _loc.TranslateAsync(values["controller"]);
    return values;
    }
    }

    Ejemplo 2: selección dinámica del controlador

    Supongamos que queremos que nuestra aplicación reciba un identificador de producto a través de una ruta con el patrón "/product/{id}/{action}" y que nos interesa que el controlador que procese estas peticiones dependa del tipo de producto (ya, sería un interés algo extraño, pero bueno...). Podríamos crear algo así:
    public class ProductTypeTransformer : DynamicRouteValueTransformer
    {
    private readonly IProductRepository _productRepository;

    public ProductTypeTransformer(IProductRepository productRepository)
    {
    _productRepository = productRepository;
    }
    public override async ValueTask<RouteValueDictionary> TransformAsync(
    HttpContext httpContext, RouteValueDictionary values)
    {
    if (int.TryParse(values["id"].ToString(), out var id))
    {
    var product = await _productRepository.GetByIdAsync(id);
    if (product != null)
    {
    var controller = product.Type switch
    {
    ProductTypes.Laptops => "laptops",
    ProductTypes.DesktopComputers => "desktop",
    ProductTypes.Tablets => "tablet",
    ProductTypes.Phones => "phone",
    ProductTypes.Tv => "tv",
    _ => "generic",
    };
    values["controller"] = controller;
    }
    }
    return values;
    }
    }
    Sencillo, ¿verdad? Como decía al principio, no es una feature para usarla todos los días, pero está bien saber que existe por si encontramos un escenario en el que pudiera venir bien esta flexibilidad para adaptar el routing a nuestras necesidades.

    Publicado en Variable not found.

    Poesía Binaria: Reanudando la marcha después de un año

    $
    0
    0

    ¡Hace poco más de un año que no publico nada! Seguro que muchos de los que leíais el blog a menudo pensabais que estaba abandonado. Lo cierto es que en este último año han ocurrido varias cosas tanto en mi vida profesional como personal que me han impedido seguir con el ritmo de publicación.
    Hace muchísimo tiempo que no hablo de algún factor personal en este blog. Llevo más de 10 años con él y 10 años dan para mucho, ¡No he celebrado el aniversario del blog! ¡No tengo perdón!

    Lo principal, el año pasado nació mi primer hijo, muy querido y deseado. Y claro, la cantidad de ratos libres durante el día desciende de manera implacable. Es más, cuando por fin tienes un rato libre, para ti solo, todo está hecho (cosa rara), y el pequeño está dormido, prefieres descansar un poco. Aún así, en este tiempo, he empezado cerca de diez posts que poco a poco iré revisando y sacando de los borradores.

    Por otro lado, a veces he escuchado a personas decir que tener un hijo les cambia la perspectiva de manera radical. Es cierto que te planteas la vida de manera distinta. Tanto que, empujado también por otros factores, dejé mi trabajo. Y desde entonces intento salir adelante como autónomo/emprendedor/mente inquieta, ofreciendo mis servicios y experiencia como desarrollador y administrador de sistemas bajo el nombre de Binarideas.
    Siempre he tenido muchas ideas, y me han gustado la programación y los retos y había muchas cosas que aprender tanto de contabilidad, organización, presupuestos, trato con clientes, fiscalidad (aunque una asesoría me lleva algunos temas, algo tiene que sonarme todo, digo yo). Además, tenía que desarrollar una serie de herramientas que me iban a ayudar a sacar adelante mis proyectos y eso me quitaba mucho más tiempo para el blog. En cualquier caso, también ofrezco servicios de desarrollo a medida y administración de sistemas. Si crees que puedo ayudarte, contacta conmigo, si vienes del blog, seguro que te hago una oferta.

    Como me dijo un amigo (no recuerdo las palabras exactas), hay que estar loco para tener un hijo y dejar el trabajo. Y no le falta razón.

    En cualquier caso, este blog quedará reservado para temas técnicos, aunque me haré algo de publicidad y, por supuesto, como persona comprometida con el software libre, muchas de las herramientas, scripts y técnicas que he desarrollado, las compartiré por aquí, comentadas y explicadas así como en plataformas como Github o Gitlab.

    También tengo que decir que la frecuencia de publicación de posts bajará un poco. Antes, intentaba tener un artículo cada semana, incluso tenía varios programados para lanzarse los lunes que coincidía con el día de más visitas (depende de la temporada cae en lunes o miércoles), pero ahora seguramente la frecuencia bajará un poco, ¡pero este blog no está abandonado!

    Eso sí, ¡mañana, toca post! Largo y muy interesante. También tengo muchos e-mails y comentarios que debo contestar. ¡Todos serán contestados!

    Foto principal: unsplash-logoKai Pilger

    The post Reanudando la marcha después de un año appeared first on Poesía Binaria.

    Viewing all 2718 articles
    Browse latest View live