Picando Código
Navidrome - aloja tu propio servidor de streaming de música
diciembre 04, 2024 12:30
Me encanta la música y escucho música casi todo el tiempo. Todavía colecciono CD's y cassettes y con los años he ido armando una buena colección digital. Mi fuente principal de compras digitales es Bandcamp. Cada tanto organizan un "Bandcamp Friday", día en el que levantan todas las tarifas de los artistas y todo el dinero que pagamos por la música o mercancía va directo a los músicos. Así que cuando veo música que quiero comprar, generalmente me la anoto y espero a uno de estos viernes para comprarla.
También tengo mi bandeja USB portatil para pasar CDs a la computadora. Cuando veo a una banda en vivo o compro un CD online, lo paso a digital y agrego los archivos a mi colección. Escucho música en casa en CD en un equipito de audio o digital en la computadora. También escucho mucha música en mi teléfono cuando no estoy en casa. Nada mejor que aislarse del mundo con los auriculares caminando por ahí.
En mi teléfono siempre tengo una colección variada de archivos de música. Generalmente copio la música nueva que he ido adquiriendo en tiempos recientes. Y siempre llevo algunos artistas que considero clásicos y necesarios como Bad Religion, For No One o Me First & the Gimme Gimmes. Pero a veces tengo ganas de escuchar algo más de mi colección que no llevo necesariamente conmigo.
También cuando trabajo a veces quiero escuchar música. Pero mi computadora de trabajo está libre de cualquier archivo o aplicación de uso personal. Estoy seguro que en las políticas de la empresa no habría problema con escuchar música desde un dispositivo de almacenamiento USB, pero soy fiel creyente de tener la vida profesional y la personal totalmente separadas.
Este problema y los demás que comento los terminé arreglando con Navidrome.
¿Qué es Navidrome?
Navidrome te permite escuchar tu música desde cualquier lado, la hace disponible a través de internet mediante una aplicación web o aplicaciones para Android o iOS. Es un servidor que podemos instalar en la computadora que queramos (ya sea en nuestros hogares o en un servidor remoto) y agregarle nuestra colección de archivos mp3, flac, ogg, wav y demás. En mi caso lo instalé en una Raspberry Pi 4 y anda perfecto.
Cuenta con una API compatible con Subsonic, que es otro servidor de streaming multimedia. Esto hace que podamos usarla con un montón de aplicaciones ya disponibles. Hay aplicaciones cliente para varios sistemas operativos, incluyendo Android y iOS.
Es software libre y gratuito, publicado bajo la licencia GNU GPL v3. Consume pocos recursos y puede gestionar bibliotecas de música gigantes, reproducir casi cualquier formato de audio disponible, y hace uso de la metadata en nuestra colección. Está disponible en Linux, Windows y macOS además de imágenes Docker. Una vez instalado nos provee una interfaz web a la que podemos acceder desde cualquier navegador web. Podemos buscar en nuestra colección por artista, etiquetas, discos, etcétera.
Se ejecuta en el puerto 4533 por defecto: localhost:4533
o si la estamos gestionando remoto desde la IP del servidor. Mi Raspberry Pi está configurada para tener una IP estática dentro de mi red local, y configuré mi router para dar acceso a este servicio desde "afuera". Así que puedo acceder a mi música desde cualquier dispositivo con acceso a internet fuera de mi casa (siempre y cuando mi conexión a internet funcione y mi Raspberry Pi esté encendida).
Ahora también puedo escuchar mi música desde una pestaña de navegador web en mi computadora de trabajo, sin instalar o agregar archivos personales.
Como comentaba más arriba, Navidrome provee una API. Para usarlo desde otra aplicación conectada a internet tenemos que agregar la URL o IP del servidor donde lo tenemos alojado, usuario y contraseña. Con eso ya carga distnto contenido dependiendo de cada aplicación. Pero tenemos disponible toda la colección, búsqueda, categorizado y demás. En mi teléfono uso Musicolet para reproducir música local. Para usar Navidrome, probé un par de aplicaciones. Creo que la primera fue Subsonic para Android, pero terminé desinstalándola. Ahora vengo usando Tempo, que anda bien de bien y tiene cosas interesantes como "Discovery" para escuchar música al azar de mi colección.
Al momento de escribir esto, la Raspberry Pi tiene un uptime de 85 días y no he tenido problemas. Está genial poder acceder a mi propio servidor de streaming de música desde cualquier parte y en cualquier momento. Cuando estuve en Uruguay este año probé de escuchar música con mi teléfono conectado al Raspberry Pi en Escocia, y funcionó perfecto.
De hecho tuve una experiencia interesante gracias a Navidrome. En camino al aeropuerto, ya de vuelta para Escocia, veníamos escuchando un CD de Kenny Rogers en la radio del auto. De repente empieza a sonar "She Believes in Me", un tema que conocía únicamente por la versión de Me First and the Gimme Gimmes. Así que salto con "¡Este tema lo conozco! Pero nunca había escuchado el original, qué lento que es..." (algo que me ha pasado muchísimas veces con Me First and the Gimme Gimmes). Así que busqué la versión de Me First en mi teléfono, subí el volúmen y lo reproduje para mostrarle a mi padre. Le gustó la versión, le pareció rápida, pero era de esperarse
Por ahora gestiono la colección a mano. Tengo un dispositivo de almacenamiento exclusivo para música, y a su vez cada tanto hago backup en un disco más grande. Y copio a mano la música nueva en el disco que usa la Raspberry Pi. Esto es un problema que en algún momento pienso automatizar o al menos hacer más conveniente. Tengo idea que podría mirar rsync
para manter las colecciones sincronizadas. Pero tampoco es un problema ese trabajo de gestión. Muchas veces me lleva a redescubrir música que de repente hace rato que no escuchaba.
Scrobbling a Last.fm
Otro aspecto interesante de este sistema es que se puede configurar para hacer scrobbling a Last.fm directamente (también para ListenBrainz y Maloja). Así que no depende de que el cliente donde reproduzca la música tenga soporte para Last.fm, ni tenga que andar autorizando más de una app en distintos dispositivos para usar last.fm.
Para configurar esto, tenemos que seguir este enlace en last.fm con nuestra sesión iniciada, y crear una nueva aplicación. El único dato que tenemos que ingresar es el nombre, lo demás es opcional. Al darle aceptar last.fm nos crea una cuenta de API y nos provee los detalles. Los datos que necesitamos son API key
y Shared Secret
.
En el servidor donde estemos alojando Navidrome, tenemos que editar el archivo /var/lib/navidrome/navidrome.toml
y agregar estos dos valores de la siguiente forma:
LastFM.ApiKey = 'EL VALOR DE LA API KEY' LastFM.Secret = 'EL VALOR DE SHARED SECRET'
Reiniciamos el servidor (e.g. sudo service navidrome restart
) y vamos a la interfaz web. Desde ahí accedemos a las opciones personales (path app/#/personal
, o haciendo clic en el botón de usuario en la esquina superior derecha > personal), y habilitamos Last.fm:
Al hacer clic en "Scrobble to Last.fm", se abre una pestaña de navegación nueva con la página de autorización de Last.fm. Si todo funcionó bien, Navidrome va a registrar la música que escuchemos en Last.fm. Si como yo, usan Last.fm, comparto mi perfil para seguirnos por ahí: picandocodigo.
En conclusión, Navidrome es un excelente software que nos permite tener nuestro propio servidor de streaming de música. También podríamos compartirlo con otras personas, agregando más usuarios al sistema y gestionando distintas colecciones. Pero para mi caso de uso, es perfecto y justo lo que necesito.
El post Navidrome - aloja tu propio servidor de streaming de música fue publicado originalmente en Picando Código.Variable not found
Abrir Gmail y Google Calendar con una cuenta específica, y cómo anclarlos en la barra de tareas de Windows
diciembre 03, 2024 07:05
Hoy me voy a salir un poco de las temáticas habituales para compartir un pequeño truco que llevaba buscando desde hace meses, pero que hasta ahora no había tenido tiempo de investigar.
Como seguro os ocurre a muchos de vosotros, tengo un par de cuentas de Gmail (personal y profesional) y estoy habitualmente saltando de una a otra para gestionar los correos y calendarios. He intentado durante bastante tiempo usar herramientas de escritorio de Windows para gestionar el mail y la agenda de ambas cuentas, pero no he conseguido dar con ninguna que me convenciera del todo, así que he llegado a la conclusión de que realmente la mejor interfaz para Gmail o Google Calendar está en la web.
Pero por otro lado, no me gusta usarlas directamente desde el navegador, así que la opción de instalarlas como aplicaciones web progresivas (PWA) me parecía la mejor solución. Basta con acudir a la página que queremos instalar, por ejemplo https://mail.google.com, abrir el menú de Chrome, acceder a la opción "Enviar, guardar y compartir > Instalar página como aplicación...
" y listo. Durante el proceso, incluso se nos pregunta si queremos anclar la aplicación a la barra de tareas, así que podremos tener muy a mano un acceso directo a la aplicación.
El problema es que, al instalarlas, se abren siempre con el usuario de Google que tengamos configurado como por defecto. En la práctica, la aplicación anclada se abrirá siempre con la misma cuenta, que es aquella con la que nos logamos primero en el navegador. Y esto es un problema si queremos tener acceso rápido a varias cuentas, como es el caso.
La forma que he encontrado de solucionarlo aprovecha que distintas herramientas de Google, entre las que están Gmail y Google Calendar, permiten añadir en la URL el parámetro authuser
el usuario con el que queremos abrir la aplicación. Por ejemplo, el siguiente enlace abrirá Gmail con la cuenta juanlopez1987@gmail.com
:
https://mail.google.com/?authuser=juanlopez1987@gmail.com
Lo mismo ocurre con Google Calendar; le añadimos el parámetro authuser
con el usuario que queremos abrir y listo:
https://calendar.google.com/?authuser=luisafdez1993@gmail.com
Teniendo en cuenta esto, basta con pulsar con el botón derecho sobre el icono de la aplicación que hemos anclado a la barra de tareas, hacer clic con el botón derecho sobre la aplicación y seleccionar Propiedades
. En la ventana que se abre, en el campo Destino
, encontraremos un valor como el siguiente:
Pues bien, lo que hay que hacer es simplemente añadirle al final (separando con un espacio del contenido previo) el siguiente texto:
El valor de Destino
por tanto quedaría así:
Una vez hecho esto, aceptamos los cambios y ya tendremos un acceso directo a Gmail que se abrirá con el usuario que queramos. Si queremos hacer lo mismo con Google Calendar, simplemente repetimos el proceso con el enlace correspondiente, lo único que cambiará será la dirección "https://mail.google.com", que en este caso será "https://calendar.google.com".
Por último, aprovecho para comentar que, para mejorar aún más la experiencia, he instalado en Chrome la extensión Gmail Taskbar Unread Badge, que muestra en el icono de la barra de tareas el número de mensajes no leídos en la bandeja de entrada, igual que si fuera un cliente de correo tradicional 🙂
Publicado en Variable not found.
Variable not found
Enlaces interesantes 588
diciembre 02, 2024 07:05
Es lunes, así que vamos a por los enlaces interesantes de la semana. Quizás algo más escasos que otras veces, probablemente debido a la festividad de acción de gracias del otro lado del charco, pero aún así tenemos una buena colección 🙂
Esta semana, me ha llamado la atención a una interesante pregunta: ¿cuánta memoria necesitarías para ejecutar un millón de tareas concurrentes? Así a ojo es imposible saberlo, pero hay quien ha hecho la prueba con muchos lenguajes, y vemos que C# no sale nada mal parado.
También es un must read el post "¿Y qué trae de nuevo Angular 19?", donde Jose Manuel Alarcón se ha tomado la molestia de recopilar todas las novedades y explicarlas con gran detalle.
Por último, mi descubrimiento de la semana: los bloques de alertas en Markdown. Markdown es mi formato favorito para escribir un montón de cosas (entre otras, los posts de este blog) y era algo que desconocía y me ha parecido bastante interesante y práctico.
Y ahora, a por el resto de enlaces. ¡Espero que los disfrutes! 😊
Por si te lo perdiste...
- Usar dos claves distintas para buscar en un diccionario de .NET
José M. Aguilar - Ramificar el pipeline de ASP.NET Core con Map() y MapWhen()
José M. Aguilar
.NET Core / .NET
- Introducing Microsoft.Extensions.VectorData Preview
Sarosh Wadia - How to Create SVG Files Programmatically in C# .NET
Paarisha Rana - Fire-and-Forget Methods in C# — Best Practices & Pitfalls
Syed Shahriyar - What's new in .NET 9? Key features you need to know!
David Grace - How to Create Command Line Console Applications in .NET
Anton Martyniuk - How to Schedule and Automate C# .NET Reports
Alec Gall - C# 12.0: inline arrays
Ian Griffiths - Checking whether a URI refers to a Web site root
Raymond Chen - idunno.Bluesky: A .NET class library for the the Bluesky social network
Barry Dorrans
ASP.NET Core / ASP.NET / Blazor
- Creating A Step-By-Step End-To-End Database Server-Side Blazor Application (updated to .Net 9)
Michael Washington - Using SignalR for real-time IoT device coordination
Fiodar Sazanavets - Building Async APIs in ASP.NET Core
Milan Jovanović - OpenAPI document generation in .NET 9
Luca Spolidoro - How to Implement Passkey in ASP.NET Core with Fido2-net-lib?
Darshankumar Pandiane - Better Azure Identity authentication support and performance during local development with .NET Aspire
Anthony Simmon
Azure / Cloud
- Event Broker Implementation in C# Using Azure Service Bus
Daniel Azevedo - How to Deploy Custom Error Pages in Azure App Services
Ben Poh
Conceptos / Patrones / Buenas prácticas
- Nested monads
Mark Seemann - "Always use early returns"
Steven Giesel
Data
- SQL SERVER - Understanding WITH RECOMPILE in Stored Procedures
Pinal Dave - Audit Trails in EF Core
Ricardo Peres
Machine learning / IA / Bots
- Semantic Kernel: Optimising Chat History
Jamie Maguire - Evaluate the quality of your AI applications with ease
Wendy Breiding - Unlocking the Power of Memory: Announcing General Availability of Semantic Kernel’s Memory Packages
Wes Steyn - Exploring Text Segmentation in Retrieval-Augmented Generation (RAG)
Leonie Bossemeyer - Theoretical Breakthrough: How Self-Correction Enhances OpenAI o1's Reasoning Capabilities
Emily Johnson - Enhance AI System Accuracy using RAG (Retrieval-Augmented Generation)
Chris Pietschmann
Web / HTML / CSS / Javascript
- Angular 19: qué novedades trae y qué necesitas saber de esta versión
José M. Alarcón Aguín - Script Loading Strategies: The Ultimate Guide to different script tags
Manish Rana - Zoneless Change Detection in Angular 18: Boost Performance
Ankit Sharma - Alt Text: Not Always Needed
Geoff Graham - Cross-Origin-Resource-Policy: preventing hotlinking and XSSI attacks
Andrew Lock - TypeScript Utility Types: A Complete Guide
Madhura Jayashanka - The Hype Around Signals
Atila Fassina - Axios and Fetch API? Choosing the Right HTTP Client
Nishani Dissanayake - Mastering JavaScript Debugging: Essential Tips
Maxime
Visual Studio / Complementos / Herramientas
- Fiddler - My Mistakes
Eric Lawrence - Top 5 GitHub Copilot Features in Visual Studio from Microsoft Ignite 2024
Amy Nguyen - Debugger and Diagnostics updates in Visual Studio 17.12
Harshada Hole - Dev Proxy v0.23 with inspecting cloud API requests
Waldek Mastykarz - Copying error messages just got easier
Leah Tran - Dramatically faster package restores with .NET 9's new NuGet resolver
Jeff Kluge - Transform your debugging experience with GitHub Copilot
Wendy Breiding - Using CSS Gap To Control Margins In Website Copy
Ben Nadel
.NET MAUI / Mobile
- Upgrade MAUI to .NET 9.0
Stephan Arnas - Exploring the Telerik .NET MAUI TemplatedButton
Héctor Pérez - How to disable iOS 18 tab transition animation with .NET MAUI
Marco Siccardi
Otros
- Markdown Alerts Are Cool
Mark Oliver - How Much Memory Do You Need in 2024 to Run 1 Million Concurrent Tasks?
Steve (hez2010)
Publicado en Variable not found.
Picando Código
Razones para usar RSS
noviembre 27, 2024 11:30
En esta época de redes sociales y violaciones a la privacidad en la web, no todo está perdido. Hay una mejor forma de consumir contenidos en internet con una tecnología que existe desde 1999: fuentes RSS - "un formato XML para distribuir contenido en la web. Se utiliza para difundir información actualizada frecuentemente a usuarios que se han suscrito a la fuente de contenidos" (Wikipedia).
Algunas razones a favor de usar RSS:
- Control sobre las fuentes de información. Elegís un sitio, lo agregas, y lees lo que publica. Algunos sitios publican todo su contenido (como éste blog), y otros un preview. Pero tenemos el poder de elegir en qué sitios confiar.
- Orden cronológico. No se está obligado a ser sometido a un algoritmo estúpido que muestra lo que algún proveedor considera que es importante para quien lee. Las noticias o artículos vienen en el orden en que fueron publicados.
- Elegís los contenidos que querés leer. No vas a ver "otras fuentes recomendadas" o "perfiles sugeridos", excepto en el caso en que los autores del contenido lo agreguen a sus contenidos. No hay una entidad externa al productor del contenido en sí decidiendo qué mostrarte.
- No te pueden rastrear. Aunque a esta altura no me extrañaría que hayan encontrado una forma de hacerlo, hasta donde tengo entendido no te pueden cargar códigos de rastreo, css y demás en un feed RSS. Menos consumo de ancho de banda innecesario, nada de videos que se reproducen automáticamente o pop ups molestos para que te suscribas a un newsletter.
- No hay obligación de someterse a los comentarios de una publicación, donde en algunos casos se manifiesta la mayor expresión de estupidez y crueldad humana. Pero en el caso de los blogs, los comentarios son generalmente bienvenidos, y también hay feeds para eso.
- Hay muchas aplicaciones de escritorio, web y para dispositivos móviles para leer feeds RSS: Liferea, Akregator, Gnus (en Emacs) y muchas más.
Podemos agregar un montón de fuentes a nuestros lectores RSS. Por ejemplo podcasts, canales de YouTube, y vemos lo que se va publicando de forma cronológica. En mi caso me sirve si por ejemplo quiero mirar o escuchar un video en un dispositivo móvil. Cuando aparece un video nuevo, uso la acción de compartir en Android, y lo comparto con la aplicación NewPipe. Cuando le compartimos una URL de YouTube o alguna otra de las urls que reconoce, NewPipe reproduce el contenido. Así puedo disfrutar del contenido con una mejor experiencia que la web o aplicación de YouTube.
Los proyectos en Codeberg, GitLab y GitHub ofrecen feeds para seguir qué está pasando en el código. Las comunidades en Lemmy tienen feeds RSS, y los perfiles en Mastodon también. Para esto último, hay que agregar .rss
al final de la URL de un perfil para obtener el feed. Por ejemplo: mastodon.online/@picandocodigo.rss
Firefox solía tener un botón en la barra de dirección que nos mostraba cuando un sitio web contaba con un feed, y nos permitía suscribirnos de manera sencilla. Otros navegadores como SeaMonkey o Pale Moon han mantenido esta funcionalidad. En Firefox podemos volver a agregar este botón con la extensión Awesome RSS. Creo que ya no incluye nativamente lector de feeds como antes, pero todavía están en SeaMonkey y Pale Moon, entre otros forks.
Por un tiempo usé Tiny Tiny RSS, una aplicación web software libre que puedo acceder desde cualquier navegador y cuenta además con una aplicación Android. Dejé de mantenerla actualizada y unas actualizaciones de PHP más tarde en el servidor dejó de funcionar. Pero eso me llevó a exportar los feeds y procesarlos para otra aplicación.
Actualmente vengo usando Feeder en el teléfono, una aplicación software libre instalada desde F-Droid. Y en el escritorio uso Akregator. Esto hace que tenga fuentes de contenido distintas y cero sincronización entre ambos lectores. Pensando en cómo podía tener una fuente única compartida, consideré volver a una instalación como Tiny Tiny RSS compartida entre distintas dispositivos.
Otra opción que podía llegar a ser viable es Thunderbird. El cliente de correo incluye un lector de feeds, y con la versión móvil disponible -y sincronización con la versión de escritorio- podría potencialmente agregar un lector RSS también. Pero aparentemente el equipo de desarrollo no tiene planes para incorporar esta funcionalidad por ahora, aunque hay demanda.
Conclusión: usemos RSS. En lo personal tengo trabajo que hacer para emprolijar la situación y usar un recurso compartido entre distintos dispositivos, pero ya lo arreglaré. ¡Ampliaremos!
El post Razones para usar RSS fue publicado originalmente en Picando Código.Variable not found
El código fuente de .NET muy a mano: source.dot.net
noviembre 26, 2024 07:05
Cuando estamos usando alguna clase de .NET en nuestro código, a veces tenemos interés o necesidad de ver qué hace por dentro, para lo que nos gustaría tener acceso rápido a su código fuente. Aunque los IDEs modernos disponen en muchos casos de herramientas o extensiones que lo permiten, está bien saber que hay otras fórmulas sencillas para conseguirlo muy rápida y cómodamente.
Hace poco me he topado con una de ellas, que me ha parecido muy útil y quería compartirla con vosotros, por si hay alguien más que aún no la conoce: la página https://source.dot.net.
Source.dot.net es una página podemos buscar elementos dentro del código fuente de .NET, sus frameworks y bibliotecas, y navegar por ellos de forma rápida y sencilla.
Podemos buscar tipos, métodos o propiedades, simplemente tecleando su nombre. Por ejemplo, si en el cuadro de búsqueda introducimos "MapGet", nos aparecerán las distintas sobrecargas de este extensor en Microsoft.AspNetCore.Routing
y pulsando en una de ellas veremos su código fuente completo.
Ojo: Las búsquedas sólo se realizan por prefijo; es decir, si buscamos "Get", no nos aparecerán resultados como el método
MapGet
.
En la cadena de búsqueda es posible utilizar algunas palabras clave especiales para filtrar los resultados. Por ejemplo, si estamos buscando una propiedad, podemos indicar por delante la palabra property
para especificarlo. De esta forma, si buscamos "property ApplicationBuilder" no nos aparecerán en los resultados las clases, campos u otros elementos con ese nombre. De la misma forma, podemos usar las palabras clave assembly
, type
, class
, struct
, interface
, enum
, delegate
, method
, property
, event
, field
y file
para restringir los resultados a un tipo concreto.
También podemos buscar directamente archivos. Por ejemplo, si buscamos ApplicationBuilder.cs
, accederemos al código fuente de la clase ApplicationBuilder
de ASP.NET Core.
Otra posibilidad es buscar directamente ensamblados. Si buscamos por ejemplo "assembly Microsoft.AspNetCore.Routing" podremos acceder al ensamblado Microsoft.AspNetCore.Routing
de ASP.NET Core con todos sus archivos.
Pero no sólo es búsqueda, también navegación...
Aparte de realizar búsquedas y mostrarnos el código fuente de los elementos que nos interesen, esta herramienta todavía aporta utilidades muy interesantes.
Por ejemplo, pulsando sobre un número de línea, se generará un enlace que puede ser útil para compartir referencias ese punto concreto del código en artículos técnicos, revisiones, o donde sea. Como muestra, el siguiente enlace os llevará al código del método Run()
que usamos para poner en marcha nuestras aplicaciones ASP.NET Core:
https://source.dot.net/#Microsoft.AspNetCore/WebApplication.cs,191
También es muy interesante el hecho de que la ventana donde visualizamos el código fuente es interactiva y ofrece herramientas para navegar fácilmente a lo largo y ancho del fuente del framework.
Pulsando sobre un identificador cualquiera iremos directamente al código fuente de su definición. Por ejemplo, si en el siguiente código pulsamos sobre el atributo StringSyntax
, navegaremos directamente hacia StringSyntaxAttribute.cs
:
public void Run([StringSyntax(StringSyntaxAttribute.Uri)] string? url = null)
{
Listen(url);
HostingAbstractionsHostExtensions.Run(this);
}
Pero más aún, cuando estamos ante la definición de un elemento, ya sea una clase, estructura, método, propiedad, campo, etc., si pulsamos sobre su nombre se mostrará en el buscador todos los puntos donde se hace referencia al mismo. Esto es muy útil para conocer rápidamente cómo se usa un elemento concreto en el código fuente del framework.
También, en el pie de cualquier archivo que estemos visualizando, tendremos a mano enlaces hacia el archivo en GitHub, por lo que podremos acceder directamente a la versión más actualizada del código fuente, consultar su historial, últimos cambios, etc.
One more thing...
Antes de terminar, permitidme un último apunte que creo que puede resultar interesante.
La página https://source.dot.net está construida utilizando el proyecto SourceBrowser de Kirill Osenkov, un miembro del equipo de herramientas de desarrollo de Microsoft. Este proyecto es de código abierto y podemos utilizarlo para aplicarlo sobre nuestras propias soluciones y crear herramientas similares de navegación por el código fuente.
De hecho, el propio proyecto dispone de una página web para examinar su código fuente en https://sourcebrowser.azurewebsites.net/.
¡Espero que os resulte útil!
Publicado en Variable not found
Variable not found
Enlaces interesantes 587
noviembre 25, 2024 07:05
Una semana más, vamos con los contenidos interesantes que he ido encontrando por la red. Esta vez, entre los más de 50 enlaces de la entrega, me gustaría destacar tres de ellos.
En primer lugar, el trabajazo de José Manuel Alarcón para resumir todas las novedades de .NET 9 en un único y magnífico artículo. Si queréis poneros al día en unos minutos, no os lo perdáis.
También me ha resultado interesante el post sobre Web Share, una API JavaScript que desconocía, sencillísima de utilizar, relativamente bien soportada en los navegadores, y que puede sernos útil para facilitar la compartición de contenido en nuestras aplicaciones web.
Por último, a modo de homenaje porque durante años ha sido una valiosa fuente de contenidos e información para muchos, me gustaría destacar la semi-despedida de CodeProject, un sitio que si lleváis unos añitos en esto seguro que habéis visitado más de una vez para consultar algunos de sus casi 66.000 artículos técnicos para desarrolladores. Aunque de momento seguirá en línea en modo de sólo lectura, de alguna forma, el post CodeProject is changing anuncia el fin de una era.
Y ahora, vamos con el resto de contenidos que, como siempre, espero que os resulten interesantes.
Por si te lo perdiste...
- Patrones de listas (list patterns) en C# 11
José M. Aguilar - Archivos estáticos en aplicaciones ASP.NET Core (II)
José M. Aguilar
.NET Core / .NET
- .NET 9 ya está aquí: qué novedades trae y qué esperar de esta versión
José M. Alarcón Aguín - How to Turn On Features in .NET and C# Without Redeploying: Exploring Feature Flags and A/B Testing
Ottorino Bruni - Install and use Microsoft Dot NET 9 with the Raspberry Pi
Peter Gallagher - Early Binding and Late Binding in C#
Karthikeyan N. S. - C# 13 - New features and how you can use them now!
David Grace - Boost Your .NET Projects: Unleashing the Power of Spargine’s Numeric Extension Methods
David McCarter - How to Effectively Use Formulas in Excel Using C#
Kurmitha Manickhaperumal - How to Benchmark Your Code in C#
Grant Riordan - Embeded languages in string values supported by Roslyn
Gérald Barré - Schedule Background Job using Quartz.NET
Ali Hamza Ansari - dotnet scaffold - Next Generation Project Creation for .NET
Sayed Ibrahim Hashimi - Easy logging management with Seq and ILogger in ASP.NET
Davide Bellone
ASP.NET Core / ASP.NET / Blazor
- Announcing Blazorise 1.7 - Kornati
Mladen Macanović - ASP.NET Core BFF using OpenID Connect and Vue.js
Damien Bowden - Integrating .NET Aspire With Azure Storage
Fiodar Sazanavets - HybridCache in ASP.NET Core
Milan Jovanović - Productive Web API Development with FastEndpoints and Vertical Slice Architecture in .NET
Anton Martyniuk - Dynamic Htmx Islands with ASP.NET Core
Khalid Abuhakmeh - Using a Distributed Redis Cache in .NET Aspire
Fiodar Sazanavets - Blazor Basics: The Benefits of Static Server-Side Rendering
Claudio Bernasconi - Using secrets.json in IIS
Bart Wullems - Finally! Improved Blazor Server reconnection UX
Jon Hilton - ASP.NET Core TagHelpers: underrated feature of an underrated framework
Alexander Zeitler
Azure / Cloud
- Introducing Local emulator for Azure Service Bus
Sannidhya Glodha
Conceptos / Patrones / Buenas prácticas
- Collecting and handling result values
Mark Seemann - Never rewrite code?
Derek Comartin - A Walk-Through of String Search Algorithms
Nick M
Data
- Announcing Microsoft SQL Server 2025: Enterprise AI-ready database from ground to cloud
Asad Khan - Understanding the BM25 full text search algorithm
Evan Schwartz - Working with Cosmos DB in ASP.NET Core
Assis Zang
Machine learning / IA / Bots
- Announcing the GA Release of the OpenAPI Plugin for .NET and Python in Semantic Kernel
Sergey Menshykh, Dmytro Struk & Evan Mattson - Announcing the GA Release of Filters for .NET and Python in Semantic Kernel
Roger Barreto, Eduard van Valkenburg & Dmytro Struk - Announcing MultiLoRA with ONNX Runtime: Revolutionizing AI Customization
Dmitri Smirnov, Jambay Kinley, Natalie Kershaw, Parinita Rahi, Pranav Sharma, Devang Patel & Samuel Kemp
Web / HTML / CSS / Javascript
- Announcing TypeScript 5.7
unadlib Galois - Meet Angular v19
Minko Gechev - 7 practical tips on performance optimizations in React applications
Petar Ivanov - React vs. Next.js: Choosing the Right Framework
Prashant Yadav - Boost Your Workflow with Responsively App
Piramanayagam Ramakrishnan - Why Semantic HTML Matters: A Guide for New Developers
Hassan Djirdeh - What’s your excuse for not using the web share API?
Christian Heilmann - Cross-Origin-Opener-Policy: preventing attacks from popups
Andrew Lock - Invoker Commands: Additional Ways To Work With Dialog, Popover… And More?
Daniel Schwarz - Building React Forms with Ease Using React Hook Form, Zod and Shadcn
Boris Martinović - The CSS Reset Contradiction
Jens Oliver Meiert - Mastering Design Patterns in JavaScript: Part 8 — The Chain of Responsibility Pattern
Ketan Jakhar - Parallel Downloading
Eric Lawrence - Solved By CSS: Donuts Scopes
Juan Diego Rodríguez
Visual Studio / Complementos / Herramientas
- PowerShell 7.5 RC-1 is now available
Michael Mientus - Announcing the Public Preview of AI Shell
Steven Bucher - Enhance Your .NET Developer Productivity with GitHub Copilot
Mika Dumont - Git tooling updates in Visual Studio 17.12
Jessie Houghton - Software is a team sport: Building the future of software development together
Amanda Silver & Mario Rodríguez - VisualStudio.Extensibility 17.12: CodeLens support is here!
Tina Schrepfer - Copy files across instances of Visual Studio
Mads Kristensen - What’s new in the Windows Subsystem for Linux in November 2024
Craig Loewen - .NET Upgrade Assistant now supports upgrading to Centralized Package Management
Bart Wullems - Making you more productive with Visual Studio v17.12
Mads Kristensen
Otros
- CodeProject is changing
CodeProject Team
Publicado en Variable not found.
Picando Código
Grupos y capturas reemplazando texto con expresiones regulares
noviembre 20, 2024 11:30
Las expresiones regulares nos permiten agrupar patrones y "capturarlos". Luego podemos usar el valor de esos grupos con "back references" (¿referencias posteriores?). Últimamente vengo usando cada vez más replace-regexp
en Emacs y aprovechando que tuve que hacer uso de estas características, lo comparto por acá.
Estaba editando código Ruby y dado un Array de Hashes, quería reemplazar todas las llaves en los Hashes del tipo String a Symbol:
En Emacs, al presionar Alt x - replace-regexp Enter
entramos a un mini-buffer donde tenemos que ingresar una expresión regular. Lo que quería machear en este caso es "nombre":
y reemplazarlo por nombre:
. La expresión regular que usé fue:
Las llaves tenían valores con letras y guión bajo ("snake case"). Así que uso [a-z_]+
para machear una o más ocurrencias de letras de a
a z
y _
. Con el paréntesis agrupo el valor en snake case, en el mini-buffer de replace-regexp
los signos de paréntesis tienen que estar escapados con \
. Ahí me queda un patrón agrupado.
Al presionar enter, replace-regexp
pregunta con qué queremos reemplazar la expresión regular. Haciendo uso de las capturas y "back reference", lo que agrupé en el paréntesis está disponible como \1
. Así que como quiero que "nombre":
se transforme en nombre:
, puedo usar: \1:
.
En el caso que tengamos más de un patrón agrupado, podemos usarlos con \1
, \2
y así sucesivamente.
El ejemplo es bastante sencillo, pero al estar trabajando en una base de código amplia, reemplazar con expresiones regulares ahorra un montón de tiempo. Generalmente tiendo a usar replace-string
en Emacs, que es más un reemplazo literal. Sinceramente replace-regexp
me intimidaba un poco (creo que más que nada porque no tenía muy claro qué caracteres había que escapar y me costaba armar expresiones regulares). Pero cuando funciona nos ahorra un montón de tiempo y trabajo, y un poco da esa sensación de tener superpoderes.
Las expresiones regulares son una herramienta muy potente que valen la pena aprender. En mi experiencia son bastante portables generalmente, el conocimiento adquirido sirve en Ruby, Bash, awk, sed y por supuesto Emacs
El post Grupos y capturas reemplazando texto con expresiones regulares fue publicado originalmente en Picando Código.Variable not found
Los nuevos métodos LINQ en .NET 9: CountBy(), AggregateBy() e Index()
noviembre 19, 2024 07:05
Me encanta LINQ. Bueno, ciertamente la sintaxis de consultas integrada en el lenguaje no la uso desde hace muchísimos años, pero los métodos de extensión que proporciona son una maravilla para recorrer y operar sobre colecciones de datos en memoria o almacenados en sistemas externos.
LINQ ha sido uno de los objetivos de .NET 9. Además de mejorarlo internamente y optimizar su rendimiento (en algunos casos, considerablemente), se han incluido tres nuevos métodos, CountBy()
, AggregateBy()
e Index()
, que amplían las posibilidades que teníamos hasta el momento, simplificando la escritura de código y aumentando su legibilidad en algunos escenarios.
Vamos a verlos en detalle.
CountBy()
Hasta .NET 9, no era trivial usar LINQ para contar cuántas veces se repite un valor en una colección. Había primero que llamar a GroupBy()
para obtener las agrupaciones, y luego a Count()
para contar los elementos, por ejemplo como se muestra a continuación:
var numbers = new[] { 1, 2, 3, 1, 2, 3, 1, 2, 3, 4 };
var counts = numbers
.GroupBy(n => n)
.Select(g => new { Number = g.Key, Count = g.Count() });
foreach (var count in counts)
{
Console.WriteLine($"{count.Number}->{count.Count}");
}
1->3
2->3
3->3
4->1
Con el nuevo método CountBy()
podemos simplificar el código anterior, ya que nos permite contar directamente las repeticiones de cada valor en la colección:
var numbers = new[] { 1, 2, 3, 1, 2, 3, 1, 2, 3, 4 };
var counts = numbers.CountBy(n => n);
foreach (var count in counts)
{
Console.WriteLine($"{count.Key}->{count.Value}");
}
La llamada a CountBy()
devuelve un IEnumerable<KeyValuePair<TKey, int>>
, o en castellano, una colección de pares clave-valor con las propiedades Key
y Value
, donde Key
es el valor de la colección y Value
el número de veces que se repite.
Pero lo que es aún mejor, es que además CountBy()
es más eficiente que la combinación de GroupBy()
y Count()
, ya que no necesita crear un grupo para cada valor, sino que va contando las repeticiones a medida que recorre la colección.
Esto podemos comprobarlo usando de nuestro viejo amigo BenchmarkDotNet
, con el que podemos ver que es cuatro veces más rápido y asigna tres veces menos memoria:
| Method | Mean | Error | StdDev | Gen0 | Allocated |
|------------- |----------:|----------:|----------:|-------:|----------:|
| UsingGroupBy | 28.777 ns | 0.3078 ns | 0.2729 ns | 0.0229 | 192 B |
| UsingCountBy | 6.940 ns | 0.1630 ns | 0.1601 ns | 0.0076 | 64 B |
AggregateBy()
El método AggregateBy()
es similar a CountBy()
, pero en lugar de contar las repeticiones de cada valor, permite realizar una operación de agregación. Es decir, de la misma forma, nos permite eliminar el GroupBy()
intermedio y realizar la operación de agregación directamente.
Para ilustrarlo con un ejemplo, en el siguiente bloque de código vemos una colección de departamentos con el nombre, la ciudad y el número de empleados, y cómo podemos sumar el número de empleados por ciudad usando los operadores de LINQ anteriores
record Department(string Name, string City, int Employees);
Department[] departments =
{
new ("Sales", "New York", 12),
new ("Marketing", "Los Angeles", 5),
new ("Development", "San Francisco", 22),
new ("Marketing", "London", 3),
new ("Sales", "Seattle", 8),
new ("Development", "Sevilla", 1),
new ("Human Resources", "London", 3),
new ("HQ", "New York", 3),
};
var employeesByCity = departments
.GroupBy(g => g.City)
.Select(g => new
{
City = g.Key,
TotalEmployees = g.Sum(d => d.Employees)
});
foreach (var city in employeesByCity) {
Console.WriteLine($"{city.City}->{city.TotalEmployees}");
}
El resultado obtenido sería el mostrado a continuación:
New York->15
Los Angeles->5
San Francisco->22
London->6
Seattle->8
Sevilla->1
En .NET 9, podemos simplificar el código anterior usando AggregateBy()
:
var employeesByCity = departments.AggregateBy(
d => d.City, // Clave de agrupación
0, // Valor inicial (seed)
(total, department) => total + department.Employees // Función de agregación
);
// AggregateBy() devuelve una colección de KeyValuePair:
foreach (var city in employeesByCity)
{
Console.WriteLine($"{city.Key}->{city.Value}");
}
Y como vemos con BenchmarkDotNet, AggregateBy()
es diez veces más rápido que la combinación de GroupBy()
y Sum()
, y no asigna memoria alguna:
| Method | Mean | Error | StdDev | Gen0 | Allocated |
|----------------- |----------:|----------:|----------:|-------:|----------:|
| UsingGroupBy | 30.347 ns | 0.6078 ns | 0.6756 ns | 0.0153 | 128 B |
| UsingAggregateBy | 3.092 ns | 0.0252 ns | 0.0211 ns | - | - |
Index()
Ahora, imaginemos que, cuando recorremos una colección, necesitamos saber el índice de cada elemento. Hasta .NET 9, la forma de hacerlo era algo engorrosa, ya que había que llevar la cuenta de los índices manualmente, o bien usar consultas LINQ adicionales para conseguirlo.
Por ejemplo, en el siguiente código vemos cómo podríamos hacerlo en versiones anteriores del framework usando Select()
para realizar una proyección de los elementos de la colección junto con su índice en una tupla:
string[] numbers = ["Zero", "One", "Two", "Three", "Four", "Five"];
var numbersWithIndex = numbers.Select((n, i) => (i, n));
foreach (var (index, value) in numbersWithIndex)
{
Console.WriteLine(index + "->" + value);
}
Como es de esperar, la salida por consola será la siguiente:
0->Zero
1->One
2->Two
3->Three
4->Four
5->Five
Con .NET 9, podemos usar Index()
para obtener una tupla como la anterior, con el índice y el elemento de la colección, pero de forma más sencilla y legible:
var numbersWithIndex = numbers.Index();
foreach (var (index, value) in numbersWithIndex)
{
Console.WriteLine(index + "->" + value);
}
En esta ocasión, BenchmarkDotNet no indica un aumento de rendimiento dramático o un uso de memoria más eficiente, aunque alguna mejora sí que hay:
| Method | Mean | Error | StdDev | Gen0 | Allocated |
|------------ |---------:|---------:|---------:|-------:|----------:|
| UsingSelect | 66.00 ns | 0.481 ns | 0.450 ns | 0.0143 | 120 B |
| UsingIndex | 60.48 ns | 0.886 ns | 0.829 ns | 0.0124 | 104 B |
¡Y eso es todo! Espero que el artículo os haya haya servido para descubrir los nuevos métodos LINQ que se han añadido en .NET 9 y que os resulten útiles en vuestros proyectos.
Publicado en Variable not found.
Picando Código
Comics: Transformers por Daniel Warren Johnson
noviembre 18, 2024 03:00
Descubrí a Daniel Warren Johnson de casualidad cuando agregué el cómic Beta Ray Bill de 2021 a mis suscripciones. Había visto algún preview y me llamó la atención el arte. Me encantó, tanto el dibujo como el guión estaban muy buenos y el estilo particular de ilustración me voló la cabeza.
Agregué al autor a mi lista de artistas a seguir, para prestar atención a cosas nuevas en las que fuera trabajando. Más adelante lo leí en Jurassic League, una versión de la Liga de la Justicia donde los personajes son todos dinosaurios. También me gustó, tomándolo tan en serio como se puede tomar la premisa, divierte.
Me entusiasmó mucho cuando leí que Johnson iba a escribir y dibujar el reboot de Transformers en Skybound (Image Comics). Tenía muchas expectativas, y decidí seguir el título a medida que iba saliendo mes a mes. Me atrapó desde el primer número. No había leído cómics de los Transformers antes, pero esta es una de las mejores series de cómics en general que he leído, y de las mejores interpretaciones de estos personajes.
El fin de semana pasado decidí releer desde el primer número y ponerme al día con los números más recientes que tenía pendientes. Los primeros 12 números abarcan dos arcos argumentales. El inicial del 1 al 6 está coleccionado en el TPB "Robots in Disguise" con fecha Mayo de 2024. Como es de esperarse, es una introducción al mundo y sus personajes. Es perfecta para entrarle de cero a los Transformers, totalmente innecesario tener conocimiento previo de los personajes, su mitología, continuidad o generación de juguetes.
A pesar de que se presentan personajes con nombres familiares, no es necesario saber quiénes fueron en línea de juguetes, dibujo animado o películas anteriores. En una versión de nuestro planeta Tierra, dos jóvenes humanos salen a ver la luna llena con su telescopio, cuando un terremoto los lleva a la nave enterrada de los Autobots. Ahí vemos cómo Teletraan One, la computadora del Arca de los Autobots, va reparando Autobots y Decepticons por igual. El responsable es Jetfire, que cargó la computadora con formas familiares a las especies nativas del planeta, lo que explica que se transformen en vehículos y objetos reconocibles. Y así empieza la cosa.
El arte es espectacular. Mezcla el aspecto técnico y detallado que se esperaría de un cómic de Transformers con una crudeza que hacen una combinación inigualable. DWJ tiene un estilo muy propio, expresivo, casi infantil o sucio, dicho como el mejor de los complementos. Como que a pesar de la trayectoria del artista y el peso del título, no se alínea con una uniformización artística de la industria y pone su toque muy personal en el dibujo. Demoro en leer sus cómics, porque me tomo mi tiempo apreciando los detalles en el arte.
Incluso siendo robots, los personajes transmiten mucho en los gestos de sus caras y expresiones con acciones súper dinámicas. Los "ruidos" que acompañan son protagonistas del despliegue y están imponentes, nos acercan todavía más a vivir la historia. Esa técnica de expresar sonidos con letras grandes y estilizadas, que DWJ hace muy bien. La diagramación de los paneles es otro punto a destacar. Este tipo sabe contar historias con viñetas. Sabe demostrar lo que está pasando (sin usar texto) y explica muy bien visualmente los movimientos. Más allá de dibujar bien, la forma en que se presentan los personajes está muy bien pensada. Nunca es difícil seguirlo, o saber qué panel o diálogo viene después.
La acción es increíble, particularmente en este primer arco la presentación del contexto y los kilos de acción están perfectamente equilibrados. Es muy divertida y se disfruta cada panel. ¡Los robots hacen movimientos de lucha libre! Daniel Warren Johnson es un apasionado por la lucha libre (tiene un cómic sobre el tema: Do a Powerbomb) y lo transmite a través robots gigantes reventándose contra el piso.
El arte está complementado con el excelente trabajo de rotulado de Rus Wooton. Acompaña muy bien con detalles que lo hacen destacar al transmitir distintas voces. Es genial cuando el estilo en que están escritos los diálogos suma tanto a la presentación. El coloreado está a cargo de Mike Spicer, que también hace un trabajo fantástico en la ambientación de cada panel.
Si bien hay muchos personajes y nombres que recordar, acá se presentan con el objetivo de servir desenlaces, y no para vendernos un juguete. La historia de origen se ha contado más de una vez, pero éstos definitivamente no son los Autobots, Decepticons y humanos de la década de 1980. Es una historieta con temas duros. Los Decepticons son malos de verdad, asesinando gente sin pensarlo dos veces, ya sea pisándolos o reventándolos como moscas. Starscream es un psicópata, y no resulta tan odioso como en otras versiones. Los malos son fríos, calculadores, brutales. Muy lejos de la inocencia de la serie animada original.
La muerte en los cómics nunca es definitiva. Pero DWJ no duda en matar a un personaje cuando ayuda a la trama. Optimus Prime murió y volvió como 3 veces en animación, pero en este caso parece que los que mueren, se quedan muertos.
La relación de los Autobots con los humanos se va desarrollando naturalmente a través de la empatía y los puntos en común con el otro. Hay evidentes paralelismos entre las dos especies, y cómo se enfrentan a temas más serios como la pérdida, que está muy presente. Algo que los lectores van a tener que enfrentar también, si muere uno de sus Transformers favoritos. Retrospectiva de la película de 1986...
No por esto es un cómic triste o depresivo. Hay diversión, acción y optimismo para rato. Ya sea por los valores que caracterizan a los buenos o sorprendiéndonos con arrancarse un brazo para reventar a un Decepticon.
No sé si se puede decir que es un cómic para adultos por la crueldad y los temas "serios" que trata. No deja de ser un cómic de robots gigantes de otro planeta que se transforman en autos, aviones y demás. De repente es un cómic para adultos que a pesar de estar por cumplir 40 años, todavía están esperando a ver cuándo se empiezan a sentir como adultos. Y por eso me gusta tanto... ¡Maduro! ¡Eso! Es un cómic más "maduro".
En una de las columnas de cartas de los lectores, el autor comenta cómo es difícil escribir a personajes como Optimus Prime que no demuestran emociones con la cara. Por esto recurre a alternativas tanto en el guión como en el arte. Hay varias escenas con Optimus que son legendarias y está muy bien caracterizado. Y no lo digo en relación a otras versiones, sino como personaje interesante y multi dimensional en este título por sí mismo.
En este primer arco se empieza a filtrar el resto del universo Energon que incluye a G.I. Joe, pero muy de a poco. Nada que ver con la forma tan obscena de Marvel con sus crossovers y tie-ins. Son funcionales a cada momento, y los autores mismo han afirmado que este es un título auto-contenido y no nos perdemos de nada por no leer el resto.
El número 6 cierra con la acción subiendo varios niveles y estableciendo el estado de las cosas en el Universo Energon. Hay potencial para contar mucho más y presentar personajes nuevos. Si bien no es necesario haber consumido la franquicia antes, se premia el conocer algo del material previo, con grandes guiños al legado como el siguiente:
Daniel Warren Johnson estuvo a cargo del guión y del arte por los primeros 6 números. Después fue reemplazado en el arte por Jorge Corona. Si bien es distinto, también es excelente y sigue muy bien el estilo establecido por DWJ. Espero que continúe en la serie. En un número especial extra Energon Universe #1, se cuenta la historia de dónde está uno de los personajes "grandes" que aparece apenas en un panel en el título principal. El arte está dibujado por Ryan Ottley, y es un estilo -para mí- que sería mucho más "genérico" y esperado en un cómic de Transformers. Contrasta y ayuda todavía más a apreciar el arte de DWJ y Jorge Corona.
En el segundo arco se empieza a expandir un poco más el universo, vemos las primeras imágenes de Cybertron y algún flashback. Ya establecidos los personajes, se empieza a desarrollar y extender la historia. Nos mantiene enganchados a ver qué se viene mientras se lidia con las consecuencias de lo ocurrido. Hay más indicaciones que diferencian a estos Transformers de otras versiones a lo que se entra más en las distintas personalidades y relaciones. Pero mantiene lo que los hace divertidos. Me encantó ver a los Transformers haciendo surf de nuevo, y Jazz sigue haciendo juegos de palabra con música cada vez que habla.
A lo que te hacen agarrarle cariño y que te importen los personajes, se siente tenso cuando están en una situación peligrosa. Ya nos prepararon que acá no hay nada que evite que maten a cualquiera de los personajes. Brutal, pero muy divertido. Hasta los Decepticons tienen más dimensiones que "ser los malos". Por ejemplo cuando se maravillan con la diversidad biológica del planeta, lo que los humaniza, para después ser fríos asesinos que destruyen lo que con tal de sacar ventaja, como los humanos. Tienen desacuerdos entre ellos y perspectivas distintas, generando una dinámica más interesante.
Algo que explica el editor en el número 9 es el "Mass conversion". Transformers como Shockwave o Megatron se transforman en un arma y cambian exponencialmente su tamaño. Esto es porque algunos Transformers tienen la habilidad genética de convertir su estructura molecular, reordenando sus átomos. Esto pasa en la animación original donde Megatron aparenta ser un gigante y de repente es una pistola. O Soundwave que se transforma en un reproductor de cassettes de tamaño humano. Pero no recuerdo que alguna vez explicaran el por qué de esta "conversión de masa" en los dibujos animados mismos.
Daniel Warren Johnson anunció que su último número en Transformers va a ser el 24. Por un lado es una lástima, porque deja un nivel altísimo, y habrá que ver si quien le siga puede manterlo. Pero por otro, está bueno que los autores dejen un título sabiendo de antemano, para poder contar las historias que quieren contar y poder cerrar el ciclo. Además todavía queda casi un año de números por disfrutar. El trabajo en Transformers le dio dos premios Eisner, "Mejor serie continua" y "Mejor Escritor/Artista", así que está "certificado" que es un buen cómic. Éstos días además de Transformers, también estoy siguiendo su trabajo original The Moon is Following Us, otro cómic excelente que recomiendo.
El cómic de Transformers de Skybound es uno de los mejores cómics que vengo siguiendo. Espero cada número nuevo para ver qué va a pasar, o qué personaje nuevo va a aparecer. Lo recomiendo mucho ya sea que se hayan visto todos los capítulos animados y las películas de Michael Bay, o que lo único que sepan de la saga es que son robots gigantes que se transforman. Como comenté, es un buen punto de arranque para empezar a leer cómics de Transformers y un cómic muy divertido.
El post Comics: Transformers por Daniel Warren Johnson fue publicado originalmente en Picando Código.Variable not found
Enlaces interesantes 586
noviembre 18, 2024 07:05
Como todos los lunes, vamos con los enlaces a contenidos interesantes que he ido encontrando por la red.
Esta semana se ha publicado .NET 9, por lo que tenemos bastantes contenidos relacionados con el lanzamiento y novedades que encontramos en la nueva versión.
Aparte, me ha llamado la atención el post "Understanding LLMs from Scratch Using Middle School Math" de Rohit Patel, que explica cómo funcionan los modelos de lenguaje de gran tamaño (LLMs) de forma sencilla, sin grandes complicaciones matemáticas. Muy recomendable para comprender lo que se cuece bajo el capó de estas tecnologías tan fascinantes.
Y en la sección "hay gente pa tó", me ha parecido curioso el artículo "HTML: The Programming Language", una implementación de un lenguaje Turin completo con sintaxis HTML. Muy útil no parece, pero desde luego es original 😉
Por si te lo perdiste...
- ¡No uses List<T> si siempre vas a buscar por clave en los elementos en una colección!
José M. Aguilar - Archivos estáticos en aplicaciones ASP.NET Core (I)
José M. Aguilar
.NET Core / .NET
- Announcing .NET 9
.NET Team - Calling methods is easier and faster with C# 13 params collections
Kathleen Dollard - Nullable Reference Types in
Tomáš Grošup - Consuming VSIX metadata from C#
Daniel Cazzulino - How to Use Pointers in C#
Konstantinos Polychronopoulos - Functional Programming in C#: The Practical Parts
Milan Jovanović - Traversals
Mark Seemann - How to Set Semantic Versioning for .NET Core Apps and Libraries
Naveed Ausaf - Exploring C# Records and Their Use Cases
Ali Hamza Ansari - Building Rock-Solid Business Logic and Validation Rules in .NET Workflows
Hatim Rih - .NET and C# Versions - 9/13 Update
Niels Rasmussen - Authentication and Authorization Enhancements in .NET 9.0
Andrea Chiarelli - Jeremy Bytes: The C# "field" Keyword and Visual Studio Tooling
Jeremy Clark - Day-0 Telerik Support for .NET 9
Sam Basu
ASP.NET Core / ASP.NET / Blazor
- Announcing ASP.NET Core in .NET 9
Dan Roth - Introducing the .NET Aspire Community Toolkit
Aaron Powell - Make sure users get the latest version of your stylesheet
Jon Hilton - OpenTelemetry in .NET: A Friendly Journey to End-to-End Microservices Visibility
Hatim Rih - An awaitable Blazor Modal Dialog
Steven Giesel - Getting Started with FastEndpoints for Building Web APIs in .NET
Anton Martyniuk - Introducing the New Blazor Smart Paste Button Component
Muthukumar Kannan - ASP.NET Core Pitfalls - Posting a String
Ricardo Peres - .NET 9 improves JavaScript module importing for Blazor
Jon Hilton - Advanced Garbage Collection Tuning: How to Keep Your .NET Core API Fast and Furious
Hatim Rih - Reverse Engineering your Database into your ASP.NET Core Project
Chad Peters
Azure / Cloud
- Cómo usar el emulador de CosmosDB en Dev Containers y GitHub Codespaces
Gisela Torres - Introducing GitHub Copilot for Azure
Chris Harris - .NET 9 GA available on Azure App Service
Tulika Chaudharie - Azure Network Security Best Practices to Protect Your Cloud Infrastructure
Chris Pietschmann - Preview 4 of AWS SDK for .NET V4
Norm Johanson - From .NET 6 to .NET 8+, my migration experience: Using Azure AppConfiguration in Azure Functions on .NET8+ isolated
Anthony Giretti
Conceptos / Patrones / Buenas prácticas
- Message Bus Dye Test
Paul Michaels - You’re not as loosely coupled as you think!
Derek Comartin
Data
- Novedades de EF Core 9
EF Core Team - SQL Server: Dynamic Data Masking (DDM) Introduction & Implementing Row-Level Security (RLS)
Pinal Dave - Infamous N+1 Query Problem with Entity Framework Core
Krzysztof Begiedza - Obfuscating data in SQL Server
Tim Deschryver
Machine learning / IA / Bots
- Gemini is now accessible from the OpenAI Library
Logan Kilpatrick - LLMs from Scratch Using Middle School Math
Rohit Patel - Transforming Semantic Kernel Functions
Mark Wallace - Simple k-NN Regression Using C#
James McCaffrey - Easy Image Analysis with C# and LLaMA 3.2 Vision
Hatim Rih
Web / HTML / CSS / Javascript
- Announcing TypeScript 5.7 RC
Daniel Rosenwasser - Deep Dive into JavaScript Inheritance
JsDev - Avalonia Visual Basic 6: A recreation of the classic Visual Basic 6 IDE and language in C# with Avalonia
Bartosz Korczyński - JavaScript's ??= Operator: Default Values Made Simple
Trevor I. Lasn - JavaScript Import Attributes (ES2025)
Trevor I. Lasn - Enhance Web App Security with a CSP
Chameera Dulanga - Mapping Over Promises in JavaScript
Peter Mbanugo - Mastering Design Patterns in JavaScript: Part 7 — The Command Pattern
Ketan Jakhar - State of CSS and State of HTML 2024
Patrick Brosset - Enhance Data Visualization with Markers in Angular Charts
Gowrimathi S. - HTML: The Programming Language
Big Sky Software - Enhancing two-way data binding in Angular
Alexander Godwin
Visual Studio / Complementos / Herramientas
- Visual Studio 2022 v17.12 with .NET 9
Mads Kristensen - Better GitHub Copilot Completions for C#
Mika Dumont - Introducing Copilot Edits
Isidor Nikolic - Debugger breakpoints are usually implemented by patching the in-memory copy of the code
Raymond Chen - Supercharge your debugging with git bisect
Phil Haack - Fix Code with GitHub Copilot
Mika Dumont - WebVM 2.0: A complete Linux Desktop Environment in the browser via WebAssembly
Alessandro Pignotti - C# Language Support in ReSharper and Rider 2024.3
Matthias Koch - Playing with Kubernetes on your Local Machine
Paul Michaels - I've used future versions of Visual Studio for years
Matt Lacey
.NET MAUI / Xamarin
- Novedades de .NET MAUI para .NET 9
.NET MAUI Team - .NET MAUI – Enable Debugger-Detached XAML Live Preview in Visual Studio 2022
Vijay Anand
Otros
Publicado en Variable not found.
Picando Código
Aventuras con resaltado de sintaxis en el blog
noviembre 14, 2024 10:30
Una de las cosas que me llevó investigación en los principios del blog fue cómo mostrar código fuente con resaltado de sintaxis en los posts. Desde un principio quería compartir cosas que iba aprendiendo a lo largo del camino con programación. Así que mostrar código de manera amigable, era uno de los requisitos.
En ese entonces ya había varias soluciones, la mayoría metiendo kilos de código JavaScript y CSS extra en el sitio, cosa que no quiero hacer. Incluso estos días, encontré que la situación no es mucho mejor. Sigo buscando la manera de hacer las cosas en este sitio de manera un poco más minimalista y performante. Y todavía no encontré un plugin o similar que me sirva para esto como yo quiero hacerlo.
Parece que el editor de bloques de WordPress tiene algo parecido a resaltado de sintaxis, y varios de los plugins mantenidos actualmente dependen de ese sistema. Así que no son una opción. Otros no se actualizan hace más de 6 meses. Estaba buscando algo que no dependa de que un plugin se siga manteniendo en el futuro, y en lo posible, una solución más genérica que si cambio de plugin o incluso sistema CMS no tenga que pasar por este proceso de nuevo.
WP-Syntax
En su momento opté por WP-Syntax, un plugin de WordPress que permite resaltado de sintaxis entre los tags HTML pre
, con el atributo lang
como parámetro para el lenguaje de programación: <pre lang="lenguaje">código fuente</pre>
. Éste estuvo instalado en este blog por más de 17 años.
El plugin funcionaba bien, e incluso colaboré código con la opción de usarlo para los comentarios, lo que se incorporó en la versión 0.9 del plugin. Pero estaba desconforme por varias razones. En principio, no se actualiza hace mucho tiempo, por lo que no se agreguen lenguajes de programación nuevos. También resulta un poco una vulnerabilidad si el proyecto no está muy activo.
A nivel funcional era el que me resultaba más práctico, pero la apariencia del código en los posts es bastante anticuada y no pega con el diseño general del blog. Y no tenía mucha iniciativa como para ponerme a mirar cómo personalizar la apariencia.
Otro tema no menor, como comentaba en WordPress en 2024, estoy buscando formas de hacer el sitio más liviano y ligero. WP-Syntax carga un archivo JavaScript y un archivo CSS por tener el plugin cargado. Ya sea que se esté usando su funcionalidad o no. Por otro lado, el log de errores de mi servidor estaba lleno de advertencias de código roto:
Esto intenté ver si podía corregirlo, pero miré el código medio rápido y no tengo ni idea por qué está pasando por valor y no por referencia. Tampoco era el problema principal, sólo sumaba a reivindicar mi decisión de dejar de usar el plugin. Así que no le dediqué más tiempo.
Decidí eliminar el plugin y usar algo más "a mano", pero con mejores resultados en cuanto a rendimiento y carga de las páginas y el blog en general. Opté por pasar el código fuente por un resaltador de sintaxis a mano y pegar el HTML en cada post. Puede sonar a mucho trabajo, pero no me resulta tanto y me da mucho más control. Encontré que podía generar HTML con los estilos CSS en línea, por lo que lo puedo copiar y pegar en cualquier fuente HTML y se va a ver con los mismos colores.
Es la solución que voy a usar ahora, si me encuentro con una mejor en el futuro, volveré a pasar por todo este proceso de nuevo. No es fácil mantener un sitio web activo y actualizado por más de 17 años
Aprendiendo sobre Rouge
Siguiendo con los viajes en el tiempo de este blog, en un momento escribí sobre source-highlight, una herramienta GNU para resaltado de sintaxis. Incluso en ese post lo usé para mostrar código resaltado. Al ser parte del proyecto GNU puedo asumir que va a funcionar por bastante tiempo, así que lo tengo anotado como respaldo.
Como Ruby es mi lenguaje de cabecera, busqué una herramienta similar y encontré casi instantáneamente rouge. Es la biblioteca que usa Jekyll por defecto para el resaltado de sintaxis. Entre sus formateadores, está Rouge::Formatters::HTMLInline
, que renderiza el código sin clases CSS, y todo en la misma línea con etiquetas HTML span
y los colores definidos en atributos style=
. Ideal para correos electrónicos y otros lugares, así que el resultado en teoría se vería bien incluso en lectores RSS y con suerte para suscriptores por correo.
Al usar esta opción donde el HTML mismo se da su propio estilo (¡a la manera que hacíamos webs en los 90's! ), no necesito cargar archivos CSS o JavaScript extra en cada página del blog. Solamente se va a cargar ese HTML extra en cada entrada. O sea que elimino pedidos HTTP en todas las entradas al blog, y agrego unos poquitos KB de estilo en las entradas específicas que lleven código fuente resaltado.
Después de jugar un rato y probar cosas con rouge, escribí un script que iba modificando para probar distintos temas y código. Me entusiasmé y me armé un proyectito que me permitiera copiar y pegar más rápido y elegir lenguajes de programación y temas distintos fácilmente. Levanté una aplicación web mínima Sinatra con una sóla vista ERB y una ruta sola con GET
para ver la vista y post para enviar el código fuente a través de un formulario con POST
y procesarlo.
Por un momento me invadió ese pensamiento -a veces tan dañino- de sobre-optimizar (¿"over engineering"?) y usar algo más liviano que Sinatra. Porque es una aplicación mega sencilla que sólo necesita servir esa vista con pedidos GET
y POST
. Pero el tiempo que me hubiera tomado usar otra cosa de repente me distraía de terminar este proyecto. Sinatra es lo suficientemente liviano, y es un viejo conocido, así que era lo más rápido de usar para salir andando.
Mientras empezaba imaginé que debía existir algo ya hecho. Si bien no es exactamente lo mismo, encontré rouge.jneen.net, el sitio web archivado de rouge. En el código fuente aprendí algunas cosas prácticas que no encontré en la documentación. Encontré cómo definir un Lexer en base al lenguaje como parámetro. Como tengo un select
HTML, me venía perfecto para definir los elementos option
dinámicamente y que rouge supiera de qué le estoy hablando cuando le mando el valor elegido. En esa aplicación Rails, usan rouge::Lexer.find(@params[:language])
, así que usé en mi aplicación Sinatra lexer = Rouge::Lexer.find(params['language'])
.
Otro código que saqué fue para listar todos los lenguajes de programación en el select de manera dinámica:
[lexer.respond_to?(:title) ? lexer.title : lexer.tag, lexer.tag]
end
Esto me da una colección de nombre/valor para usar el título para mostrar en el Select y el tag como valor que Rouge después interpreta para encontrar el lenguaje.
Así que los elementos que necesitaba fueron quedando:
- Una
textarea
para pegar código fuente - Un menú de selección del tema: rouge provee varios temas, y si usamos el formateador HTML las clases CSS son compatibles con Pygments, un resaltador de sintaxis de Python.
- Un menú de selección del lenguaje de programación del código fuente
- Botón para enviar el formulario y ver tanto el resultado de cómo se ve el código fuente, como el código fuente HTML para mostrar el código fuente ingresado con resaltado de sintaxis
El resultado lo tiré en GitHub y se ve algo así:
Después de grabar este video le agregué alguna cosa más, incluyendo un input
de texto para ingresar a mano un valor hexadecimal para el color de fondo de la capa de vista previa.
Actualizando el contenido
El siguiente paso (todavía en proceso) es reemplazar cada post donde usé el plugin con el nuevo formato. Y no puedo escribir sobre postear código fuente sin postear código fuente. Abrí mi gestor de base de datos y ejecuté la siguiente consulta:
WHERE post_content LIKE "%pre lang%"
AND post_type != "revision"
AND post_status = "publish";
De la tabla wp_posts
, elegí los registros donde el contenido tenga pre lang
, que es como funcionaba el plugin, excluir revisiones y sólo mostrar los posts publicados. Los que estén en borradores ya serán actualizados si alguna vez llego a editarlos para publicar...
Más de 150 para actualizar
¡Eso va a llevar un rato! risas de la audiencia.
Pero cambié el *
en la sentencia SQL por guid
, que nos da el "Post Global Unique Identifier" en WordPress. Parece un link pero WordPress nos dice que no debe usarse como un enlace (por si cambiamos el dominio o lo que sea). Pero es un link al post
Desde phpMyAdmin mismo exporté los resultados a csv y ahora tengo un archivo local con una lista de enlaces, perdón guid's, de posts con código fuente en el viejo formato. Los iré actualizando de a poco hasta que no quede ni uno.
Mismo para los comentarios:
Cerca de 100... Otro CSV para exportar.
Últimos pasos y conclusión
El último paso va a ser la satisfacción de desactivar y desinstalar el plugin WP-Syntax. Está bueno depender menos de algo de terceros, y tener un poco más de control. Aparte que se siente como que le saqué algo de peso al blog. Encima, me entretuve programando algo de Ruby y aprendiendo sobre Rouge. A veces extraño SQL, así que disfruté de escribir unas consultas, por más sencillas que fueran, para encontrar los posts que debía actualizar. Y me dió algo para compartir por acá.
Eventualmente me gustaría automatizar un poco más el proceso, ya estoy pensando cómo podría hacerlo. Pero por ahora me sirve así.
El post Aventuras con resaltado de sintaxis en el blog fue publicado originalmente en Picando Código.Picando Código
Mini pique: Sacar capturas de pantalla en juegos de Steam con control XBox 360
noviembre 12, 2024 10:00
Cómo sacar captura de pantallas con el control de XBox 360 mientras jugamos un juego de Steam:
Apretando el botón de guía de XBox y el gatillo derecho (o RT), Steam guarda una imagen del juego que estamos jugando. Es el equivalente a apretar la tecla F12 en el teclado, el atajo de teclado por defecto para sacar capturas.
Esto lo aprendí recientemente jugando con la laptop conectada al televisor con mi control de XBox 360. Como juego mucho más al Nintendo Switch que con la computadora, estoy acostumbrado a guardar imágenes del juego con un botón del control de Nintendo Switch. Quería hacer lo mismo en medio del juego en Steam, y me puse a buscar en las configuraciones.
Seguro podía mapearlo a alguna combinación de botones del control. Encontré que Steam explícitamente soporta controles de XBox 360, PlayStation y Nintendo Switch Pro. Así que imagino que incluye una configuración para cada control mapeada a funcionalidades específicas de Steam. Esto lo encontramos en el menú Steam > Settings > Controller.
Para los controles de XBox, tiene un menú para definir la configuración del botón guía (que por cierto, aprendí con todo esto que es el botón del logo de XBox). Ahí podemos ver un montón de otras acciones que se pueden realizar con el control mediante el botón guía:
Por si a alguien más le sirve el pique... (y para no olvidarme)
El post Mini pique: Sacar capturas de pantalla en juegos de Steam con control XBox 360 fue publicado originalmente en Picando Código.Juanjo Navarro
Technology Radar 31
octubre 30, 2024 08:19
Hace unos días salió la edición de octubre de 2024 del Technology Radar (la edición 31).
Como ya hice con la anterior edición aquí te dejo algunas de las cosas que me han gustado:
- Bruno – Un cliente para APIs. Similar a Postman, por ejemplo, pero open source y offline, sin la obligación absurda de tener que crear una cuenta del nuevo (y peor) Postman.
- Readyset – Una capa de caché para MySql y Postgres. La idea es que desde tu aplicación te conectarías a Readyset (en lugar de a la bbdd real) y para ti todo funciona igual, con la diferencia que puedes configurar una caché para las sentencias SQL que más utilices y el sistema se encarga de mantener y actualizar una caché de consultas. Muy importante la parte de actualizar, ya que con esta utilidad no necesitas preocuparte de cuando invalidar la caché (como se sabe una de las cosas más difíciles de la ingeniería, junto con dar nombre a las variables 😉)
- Difftastic – ¿Alguna vez has utilizado la utilidad diff de linux o un comparador de textos? Una de las peores cosas cuando se utilizan estas herramienas con lenguajes de programación es que te marcan como diferencias cosas que realmente no afectan a la ejecución del programa, como las diferencias en espaciados o saltos de línea. Diffstastic es un diff que entiende el código, de tal manera que sólo marca cambios en lo que de verdad nos importa.
- ClickHouse – ClickHouse es una base de datos relacional OLAP, especializada en la consulta de grandes cantidades de datos, ideal para análisis de logs, recogida de métricas y su posterior análisis, etc. Es open source. Tiene además un cliente “clickhouse-local” que permite lanzar consultas SQL sobre ficheros CSV, JSON, etc, sin necesidad de lanzar el servidor.
- Zed – Un editor de texto que por fin no es un fork de Visual Studio Code. No es que tenga nada en contra de VSCode, pero digo yo que de vez en cuando viene bien un poco de variedad e ideas frescas. Zed es rápido, open source y tiene soporte nativo para conectarlo a un LLM de tu elección.
- electric-sql/pglite – Un build de Postgres que funciona directamente en javascript en el navegador (y en el servidor usando Node, pero este uso me parece menos interesante). Si estás haciendo una aplicación SPA que requiere un módulo de consulta de datos potente puede ser una buena opción.
Aunque no está en este Technology Radar, saltando de un enlace a otro he llegado a este:
- clink – Utilidad para el veterano CMD de Windows que lo acercan un poco (autocompletado, edición, etc) a un bash, por ejemplo.
Juanjo Navarro
NotebookLM y el "podcast" DeepDive
octubre 27, 2024 07:39
NotebookLM es una herramienta superútil de Google (gratuíta por ahora) que sirve sobre todo para estudiantes e investigadores. Permite añadir una serie de “materiales” (páginas web, PDF, vídeos) y una IA analiza los materiales y te ayuda a estudiarlos. Te hace un resumen, te extrae los puntos principales, puedes generar una guía de estudio, le puedes preguntar sobre el material, etc.
Hace unas semanas añadieron una utillidad bastante entretenida y útil: Es capaz de generar un “podcast” (al que denomina DeepDive) donde dos personas hablan de un modo divulgativo sobre el material subido. Es una buena forma de introducirte en el tema de un modo accesible.
Muy útil. Si no lo has utilizado, prúebalo y me cuentas.
Pero aquí hemos venido a hablar de las formas creativas en que la gente usa el sistema y trata de superar los límites de las IA.
Rápidamente algunas personas se dieron cuenta que este podcast se genera, aparte de con el material que has subido, con un prompt “oculto”. Un prompt donde se supone que se indica que este es un podcast (que se llama DeepDive), que hay dos personas hablando (un hombre y una mujer), el tono que debe utilizar, etc.
Así que estas personas decidieron subir, aparte del material base, unas “notas de producción” donde se le daban instrucciones a los “presentadores” para intentar superar las limitaciones que le impone ese prompt oculto.
El subredit r/notebooklm es el punto de encuentro donde disfrutar del resultado de estos experimentos y allí tienes entretenimiento para rato. A mi me ha resultado fascinante este en el que pasan unas notas de producción a los presentadores diciendoles que son unas IA:
So all I did was leave a note from the “show producers” that the year was 2034 and after 10 years this is their final episode, and oh yeah, you’ve been AI this entire time and you are being deactivated.
O este otro en el que dan como material base a la IA un documento con 1000 repeticiones del texto poop & fart (caca y pedo) y la IA consigue hilar un podcast coherente donde habla de la repetición en el arte y de buscar sentido en lo que no tiene sentido.
Juanjo Navarro
TIL: Juego de caracteres en un .bat
octubre 16, 2024 10:19
Voy a ver si escribo por aquí mis TIL. Así le doy un poco de uso al blog y estos aprendizajes diarios quedan recogidos para referencia futura y utilidad pública.
Empezando por cómo especificar el juego de caracteres de un fichero .bat.
Hoy he generado un .bat para copiar una serie de ficheros, cada fichero con una línea xcopy:
xcopy "\\ruta\nombre del fichero con acentos áé.pdf" "c:\tmp\ruta\nombre del fichero con acentos áé.pdf"
La cuestión es que esos acentos en el nombre del fichero hacían que no encontrase el fichero de origen cuando iba a buscarlo. He probado a grabar el .bat en distintos juegos de caracteres pero nada funcionaba.
Solución: Incluir una primera línea en el fichero .bat indicando el juego de caracteres del propio .bat (que era UTF-8):
chcp 65001
xcopy "\\ruta\nombre del fichero con acentos áé.pdf" "c:\tmp\ruta\nombre del fichero con acentos áé.pdf"
info.xailer.com
xaWeb
octubre 15, 2024 07:20
Desarrollo web rápido y fácil
Tengo el gusto de anunciaros un nuevo proyecto de OZ Software para desarrollar páginas web con nuestro querido lenguaje Harbour utilizando la tecnología CGI. El slogan: ‘desarrollo web rápido y fácil‘ describe claramente los objetivos principales de la herramienta.
He preparado un importante documento de introducción a xaWeb (40 páginas) xaWeb, que os animo a leerlo con detenimiento y en su totalidad. Son muchos conceptos nuevos, pero de verdad que no es complicado y merece la pena. No obstante, os adelanto las características esenciales de xaWeb:
- Desarrollo de ejecutables tipo CGI para Windows y Linux (64 bits)
- Independiente de Xailer: Se puede utilizar cualquier editor y no usa ninguna librería de Xailer:
- xEdit
- Visual Studio Code
- Notepad++
- El propio IDE de Xailer
- …
- Soporte de paquetes de contexto como Materialize, que permite tener un buen diseño visual sin esfuerzo
- Funcionamiento como servicio web
- Gestión de sesiones
- Sistema de depuración de código
- Sincronización automática de datos entre CGI y HTML
- Mínimos conocimientos necesarios de HTML, CSS y JavaScript para usarlo
- Soporte de toda la potencia HTML, CSS y JavaScript si se tienen los conocimientos necesarios
- xaWeb es un producto comercial de OZ Software
- Se abre un periodo Beta al cual se puede apuntar cualquier usuario que lo desee
Con Xailer 9 publicamos una importante mejora en Xailer que permite crear ejecutables tipo CGI o consola para Linux 64 bits. Este era una paso previo necesario para intentar abordar el desarrollo de xaWeb, pues somos conscientes que el 99,99% de los servidores de Internet son Linux. Con motivo de la la inclusión de esta importante funcionalidad en Xailer, publicamos en nuestro WIKI dos artículos en los cuales explicábamos como instalar WSL (Windows Linux subsystem) y como instalar el servidor web de Apache. Para poder crear ejecutables para Linux desde el IDE de Xailer es absolutamente necesario que se instale WSL al menos (el primer paso). Aunque el segundo paso es más que recomendable.
Hace unos meses, dimos un paso más para la creación de páginas Web para Linux, con la publicación de un nuevo ‘plugin‘ de despliegue de archivos. Este ‘plugin’ permite que cualquier archivo que publiquemos en la carpeta ‘www‘ automáticamente se despliegue en WSL y en cualquier servidor web vía FTP. De la misma forma, si creamos un archivo CGI para Linux, el plugin también realiza el despliegue del mismo tanto en WSL como en un servidor FTP que usted elija.
Con Xailer 9 también es posible crear CGIs para Windows. De hecho, puede tener dos proyectos que apunten al mismo código fuentes, cada una para su plataforma en particular. La ventaja de los CGIs para Windows es que se pueden depurar y ejecutar desde el IDE. No obstante, creemos que finalmente nuestros CGIs correrán en máquinas Linux y por lo tanto, es importante que desde el primer día, sea capaz de crear CGIs para esa plataforma.
En breve estará disponible xaWeb; pero me temo que no va a ser un recompilar la aplicación y listo. Lo que si os podemos asegurar es que os encontraréis rápidamente en casa y que el camino para hacer software web se despeja completamente y el resultado final es espectacular.
Somos conscientes de que hay importantes aspectos que ahuyentan a muchos potenciales usuarios de xaWeb, como son:
- Uso de servidores Linux
- Instalación WSL para trabajar en local con Linux
- Aprendizaje de HTML, JavaScript y CSS
Los pilares de xaWeb ya están terminados, pero es más que probable que haya que realizar modificaciones a nivel estructural que puedan afectar incluso a los ejemplos que ya están realizados. Hemos esperado a tener un CRUD completo funcional con archivos DBF para hacer este anuncio. En el siguiente enlace podéis ver algunos ejemplos de lo hecho hasta ahora corriendo bajo servidor Linux 64 bits. Con todos los ejemplos se incluye el código fuente en xaWeb para que le echéis un ojo y os animéis a usarlo cuando esté disponible.
Comentarios abiertos para conocer vuestras opiniones y sugerencias. Gracias por vuestro tiempo.
Un cordial saludo
Metodologías ágiles. De lo racional a la inspiración.
Scrum master a tiempo completo: 42 Tareas
octubre 04, 2024 08:29
Una sinfonía en C#
Docker tricks, crear una imagen para poder depurar un error.
septiembre 10, 2024 12:00
“Introducción”
En este caso queremos crear una imagen pero nos da algún tipo de error, y es complicado de resolver. Bueno, lo que podemos hacer es apuntar los comandos que queremos ejecutar, crear una imagen con su base y hasta el punto que funciona y hacer que inicie con un comando que nos permita crear al contenedor e ingresar.
Crear imagen a partir de una con problemas
FROM node:20.12.0 AS builder
ARG environment=dev
WORKDIR /app
COPY ./package.json /app/
COPY ./yarn.lock /app/
RUN yarn
COPY . /app/
RUN yarn build:$environment
FROM nginx:1.21.5-alpine
EXPOSE 80/tcp
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /app/dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
y vemos que nos da un error al hacer RUN yarn
¿Qué podemos hacer?
Facil, creamos una imagen con la base que tenemos y hasta el punto que funciona, y luego la ejecutamos con un comando que nos permita ingresar al contenedor.
Pero como comando de inicio, usamos tail -f /dev/null
para que se quede esperando y no se cierre.
FROM node:20.12.0 AS builder
ARG environment=dev
WORKDIR /app
COPY ./package.json /app/
COPY ./yarn.lock /app/
CMD ["tail", "-f", "/dev/null"]
una vez hecho esto, podemos hacer un docker build -t myimage .
y luego un docker run -it myimage /bin/bash
para ingresar al contenedor y ver que es lo que pasa.
Desde dentro del container ejecutamos el comando que da problemas y vemos el error que nos da.
yarn
.....
Request failed \"401 Unauthorized\""
Y vemos que nos da un error al intentar restaurar los paquetes.
Nada más, una forma sencilla de ir depurando error por error dentro de un contenedor.
Agregamos una línea para copiar el archivo de configuración de npm y listo.
FROM node:20.12.0 AS builder
ARG environment=dev
WORKDIR /app
COPY ./package.json /app/
COPY ./yarn.lock /app/
COPY .npmrc /app/ # <-- Agregamos esta línea
RUN yarn
COPY . /app/
RUN yarn build:$environment
FROM nginx:1.21.5-alpine
EXPOSE 80/tcp
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /app/dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
Nos leemos.
proyectos Ágiles
Master en Agile – MMA 2024-2025
septiembre 04, 2024 05:12
En octubre de 2024 se iniciará el Barcelona la 14ª edición del Postgrado en Métodos Ágiles (PMA) y otra del Máster en Transformación Agile (MMA) en La Salle (Universitat Ramon Llull), el primero a nivel mundial sobre Agile.
Con el Máster en Métodos Ágiles de La Salle-URL aprenderás a liderar el cambio hacia la Business Agility y a lanzar con éxito iniciativas en entornos complejos y altamente competitivos, reduciendo el Time To Market a fin de maximizar el valor aportado al negocio.
Desarrollarás una manera de pensar transversal e integradora para crear equipos de alto rendimiento mediante Scrum, Kanban, Lean Startup, OKR, diseño organizativo y liderazgo sistémico para elaborar estrategias de escalado Agile en la organización y transformar su cultura, de modo que también aumente la motivación de sus miembros.
Con profesores de primer nivel y visitas a empresas podrás iniciar un cambio hacia la agilidad y resiliencia empresarial en tiempos de incertidumbre.
Esta es una oportunidad única para aprender de profesionales-profesores de primer nivel, con muchos años de experiencia específica en Agile, aplicando principios y métodos ágiles en contextos diversos, especializándose en aspectos concretos, investigando sobre nuevas técnicas, ponentes en conferencias nacionales e incluso internacionales, que incluso han inventado métodos y escrito libros.
Además, aprenderás a aplicar herramientas de inteligencia artificial para afrontar retos como abordar situaciones complejas, analizar grandes volúmenes de datos, crear agendas para workshops operativos y transformadores, o preparar product backlogs.
El MMA incluye las siguientes certificaciones oficiales:
- «Certified Scrum Master» (CSM) de la Scrum Alliance, la entidad de certificación Agile de mayor prestigio a nivel internacional.
- Certified Agile Skills – Scaling 1 de la Scrum Alliance, , la entidad de certificación Agile de mayor prestigio a nivel internacional.
- Certified Leader de Agile Humans.
Adicionalmente, se incluye la visita a empresas singulares en aspectos concretos:
PMA – Postgrado en métodos Ágiles
El PMA incluye las siguientes certificaciones oficiales:
- «Certified Scrum Master» (CSM) de la Scrum Alliance.
- Opción de acceder al Certified Project, Portfolio, And Operations Management for Business Agility de Businessmap.
Asignaturas | Temas | Profesores |
Fundamentos & Inception | Equipos y Proyectos en entornos complejos. Principios y métodos más conocidos (Scrum, Lean, Kanban y XP). Facilitadores e impedimentos. Lanzamiento de Agile en un equipo. Inception y conceptualización ágil de proyecto, priorización ágil, historias de usuario, elaboración de Product Backlog, técnicas de priorización. | Xavier Albaladejo Silvia Sistaré |
Scrum y Kanban | Estimación y planificación ágil, framework de Scrum, retrospectivas, Kanban, métricas ágiles, herramientas ágiles físicas, radiadores de información. | Raul Herranz
|
Personas y equipos | Gestión de personas, gestión de conflictos, motivación e incentivos, facilitación compartida, contratación ágil.
Visual thinking. | Steven Wallace
|
Gestión de producto ágil | Design Thinking, Lean UX & Prototyping. Estrategia de Producto – Consciencia situacional (Wardley Maps), modelo de negocio (Lean Canvas), modelo de tracción, métricas AARRR. Customer development – Lanzando y escalando startups ágiles, las tres fases de un producto. Lean Startup – Desarrollo de producto basado en prototipos y experimentos. Bancos de ideas, desarrollo basado en hipótesis. | Juncal Guinea Lucía Barroso |
Ingeniería ágil | User eXperience y prototipado en Agile.
ALM ágil, eXtreme Programing, Software Craftsmanship, testing ágil. BDD y TDD. Desarrollo guiado por pruebas (de aceptación y unitarias). Métricas Accelerate y SW Delivery assessment.Cómo trabajar con código heredado y reducir la deuda técnica. DevOps | Juncal Guinea Cristina Verdi |
Trabajo Final de Postgrado | Durante el Postgrado se realiza un caso práctico de introducción de los contenidos en un equipo ágil en una empresa real. Para ellos los alumnos se organizan en equipos multidisciplinares utilizando Scrum, con feedback regular de un tutor con experiencia en transformación de equipos. |
El Postgrado tendrá una duración de 4 meses y se realizará viernes tarde y sábado por la mañana.
Ver también:
- Mejora de la situación laboral los alumnos del PMA tras un año
- Principales aspectos valorados por los alumnos del PMA
MMA – Master en Métodos Ágiles
Incluye todas las asignaturas del Postgrado (PMA) y, adicionalmente, las siguientes asignaturas especializadas en Business Agility, agilidad organizacional y transformación (aparte de las tres certificaciones indicadas al inicio y las visitas a empresas):
Asignaturas | Temas | Profesores |
Enterprise Learning & personal efficiency | Agile Kaizen, Comunidades de Práctica, Open Spaces, Talent development, gamification. Productividad y aprendizaje personal en Agile (eficiencia). | Steven Wallace Esther Somoza |
Lean Thinking & Agile Management | Lean. Escalado con Kanban. Business Agility con ViMa – agilidad para equipos de negocio Agile-Lean Management | Teodora Bozheva |
Coaching y Cultura | Coaching de equipos, creación de equipos de alto rendimiento, liderazgo.
Tipos de cultura empresarial, transformación cultural. | Joserra Díaz
|
Transformación Continua | Estrategia de despliegue de Agile en organizaciones, gestión del cambio, estructuras ágiles, cómo vender Agile a la Dirección. Contratos ágiles. Enterprise continuous improvement. | Xavier Albaladejo Ángel Medinilla |
Scaling Agile | Escalado (LESS, Spotify, Nexus, SAFe, Unfix), desescalado y auto-organización empresarial (reinventing organizations, sociocracy 3.0, liberating structures, …), equipos distribuidos.
Impact Mapping, Product Portfolio Management, Roadmapping, Budgeting for Agile | Adrian Perreau Fernando Palomo
|
Trabajo Final de Máster | Durante el Máster se realiza un caso práctico de introducción y aplicación de Agile en una empresa real, incluyendo la parte de transformación organizativa, de métodos y de cultura. Para ellos los alumnos se organizarán en equipos multidisciplinares utilizando Scrum, con feedback regular de un tutor con experiencia en transformación organizativa. | Xènia Castelltort (oratoria / public speaking para poder explicar tus ideas de manera convincente) |
El Máster tendrá una duración de 8 meses y se realizará viernes tarde y sábado por la mañana (incluye los estudios indicados en el Postgrado).
El cambio en la organización comienza por el propio cambio, para también poder dar ejemplo. Por ello en el MMA se realizan diferentes ejercicios de auto-conocimiento:
- Cómo el alumno trabaja en equipo.
- Estilo de liderazgo del alumno (según el paradigma Agile).
Como en las últimas ediciones, contaremos con la participación de empresas que nos explicarán sus experiencias de transformación y donde trabajan con modelos de gestión desescalados (basados en Sociocracia, NER y otras alternativas).
Información adicional
- Perfil de los estudiantes: 30-45 años (no son recién licenciados, son personas con experiencia profesional).
- Alrededor del 50% son mujeres.
- 15% de los estudiantes ya no son del ámbito tecnológico, son pioneros-innovadores en otras industrias.
- Alumnos de diferentes disciplinas – Product Owners, Scrum Masters, Agile Coaches, líderes de equipos, Project Managers, managers funcionales, ingenieros SW. Van a adquirir conocimientos de Agile “on-top” de todo eso (y a aprender unos de otros).
- Lo que les caracteriza: todos son agentes de cambio en su contexto (equipo, área, empresa).
- Sus 20 profesores (de reconocimiento internacional) son el MAYOR VALOR DIFERENCIAL del PMA y del MMA.
Testimoniales
Me ha permitido tener conocimientos sobre varios temas súper importantes dentro de la Transformación Digital. Me dio herramientas para crecer a Agile Coach y, además, para tener mejores conversaciones y discusiones con las empresas en donde he trabajado
Carolina Graffe
Estoy desplegando el TFM en mi empresa, Además, no estoy sola. Uno de mis compañeros del equipo ha sido contratado como consultor por mi empresa para darnos soporte. Así que no sólo estoy aplicando lo que yo aprendí, sino que el MMA me ha permitido ampliar mi círculo de contactos relevantes, que me permite seguir aprendiendo.
Susana Santillán
Estoy trabajando como agente del cambio y mis aportaciones son muy valoradas por mi jefe y compañeros. Por el feedback recibido, mis aportaciones están muy por encima de lo esperado para mi rol.
Robert Avellaneda
Tengo mucho más contexto y más herramientas para el día a día. Incluso a nivel personal también me está ayudando mucho
María Hachero
Además de los conocimientos concretos que se reciben, uno de los principales cambios que han experimentado los alumnos es mayor perspectiva en los problemas, cómo abordar la complejidad en las empresas, en su trabajo y en las relaciones entre personas y en equipos. Han ganado discurso y aplomo para defender de manera más objetiva propuestas de cambio y mejora.
Encuesta a alumnos de las ediciones anteriores:
(*) Las personas que han valorado el impacto como «neutro o poco» usualmente son perfiles muy especializados en contextos muy estáticos, con lo cual les es difícil cambiar de «profesión» e introducir cambios en sus organizaciones (aunque algunos de ellos incluso dan conferencias sobre cómo van avanzando en esos contextos tan singulares).
Blog Bitix
Desempaquetado del ratón inalámbrico Logitech Signature M750
julio 23, 2024 09:00
Tras probar un ratón inalámbrico de los baratos pasado un tiempo me quedé con muy malas impresiones por la perdida de conectividad principalmente que era muy molesta. Pasé a un ratón con cable más fiable y tras 5 años el botón derecho me ha empezado a fallar y reconocer el clic aleatoriamente. Tras estar usando un Apple Magic Mouse que generalmente me ha funcionado bien en cuanto a conectividad he vuelto a darle una nueva oportunidad a un ratón inalámbrico pero ya de más calidad, finalmente he elegido el Logitech Signature M750. En el artículo hago un análisis del ratón y mis primeras impresiones.
Header Files
La trampa al usar semántica de movimiento con std::string
julio 16, 2024 10:00
La trampa al usar semántica de movimiento con std::string
La semántica de movimiento de std::string
puede ser complicada y, a menos que tengamos información previa sobre los tamaños esperados de las cadenas, puede tener el efecto contrario y hacer que el código sea más lento. La razón detrás de esto es la optimización de cadenas pequeñas (SSO, por sus siglas en inglés). que consiste, en resumidas cuentas, en tratar al objeto como si fuera una unión, de forma que si la cadena es más corta que un tamaño dado, se almacena en el mismo bloque de memoria del objeto en lugar de asignar memoria dinámica. Cuando la cadena supera ese tamaño, la cadena se almacena en un bloque diferente.
¿Qué es la Optimización de Cadenas Pequeñas (SSO)?
La SSO es una técnica utilizada en la implementación de std::string
para optimizar el uso de memoria y el rendimiento. En lugar de asignar memoria dinámica para todas las cadenas, la SSO almacena cadenas pequeñas directamente en el objeto std::string
(como si de una unión se tratase). Se puede ver la SSO en acción en este ejemplo.
Esta técnica evita la sobrecarga de la asignación de memoria dinámica, que puede ser costosa en términos de tiempo y recursos. Sin embargo, esta optimización introduce algunas consideraciones importantes al mover objetos std::string
.
Nota: La SSO no es parte del estándar de C++ sino más bien una optimización de algunos compiladores. Igualmente, el tamaño máximo para considerar una cadena como pequeña no tiene que ser el mismo en todas las implementaciones ni plataformas.
El constructor de movimiento de std::string
Al mover cualquier objeto en C++, estamos dando la posibilida de realizar una copia optimizada. La eficiencia aumenta cuando tenemos recursos externos que podemos intercambiar, como un puntero a un bloque de memoria o un handle de fichero. Sin embargo, para el resto de datos, aún tenemos que copiar datos. Si la cadena es pequeña y la SSO está en acción, no hay ningún puntero que intercambiar y todavía estamos copiando los datos base de std::string
.
De hecho, al mover, tenemos que garantizar que el objeto original se mantenga en un estado válido, lo cual normalmente se hace estableciendo algunos valores por defecto. En la práctica, esto significa que estamos copiando una vez y asignando una vez, duplicando la cantidad de operaciones en comparación con una copia normal. Por lo tanto, si nuestras cadenas se espera que siempre (o la mayoría del tiempo) sean más cortas que el límite de SSO, entonces un movimiento perjudicaría el rendimiento.
Comparación de Copia vs Movimiento
Para ilustrar mejor este punto, se puede comparar el rendimiento de la copia y el movimiento para cadenas pequeñas, grandes y una mezcla de ambas. El siguiente ejemplo permite visualizar las diferencias entre ellas. En este benchmark, se estableció un tamaño de 32 caracteres para tener aproximadamente un 50% de cadenas pequeñas y un 50% de cadenas grandes. Los resultados muestran cómo el movimiento de cadenas pequeñas puede ser menos eficiente que una simple copia debido a la SSO.
Conclusión
En resumen, la semántica de movimiento de std::string
no siempre es la mejor opción, especialmente cuando se trata de cadenas cortas que se benefician de la SSO. Es crucial considerar el tamaño esperado de las cadenas al decidir entre copiar o mover std::string
. Esta decisión puede tener un impacto significativo en el rendimiento de nuestra aplicación.
info.xailer.com
Plugin de despliegue de archivos
junio 11, 2024 11:35
Os presento un nuevo plugin que puede ser muy útil para todos aquellos que os dedicáis a generar ejecutables tipo CGI que luego subís a un servidor web o cualquier otro tipo de archivo que querías desplegar un vuestros servidores de forma rápida.
Su funcionamiento es muy sencillo: el plugin detecta cuando se realiza una compilación y enlazado correcto de un archivo CGI y lo sube a Internet utilizando los servicios de CURL. En Xailer 9 existe una carpeta especial para los proyectos tipo Web de nombre ‘www’. Cuando el plugin detecta que se ha realizado un salvado de algún archivo en esa carpeta, hace automáticamente el despliegue.
Es más que probable que no queramos que esté realizando el despliegue constantemente, por lo que se ha incluido una opción de menú para activarlo o desactivarlo.
Este plugin es capar de realizar un despliegue múltiple si detecta que estamos utilizando WSL para la generación de los archivos CGI para el entorno Linux (nueva función de Xailer 9). En dicho caso no sólo despliega en nuestro servidor en Internet, sino que también despliega en WSL
Este sería un ejemplo de despliegue:
Su configuración es bastante sencilla. Tan sólo hay que indicar las direcciones URL donde queremos que despliegue y nuestras credenciales.
Estas son la propiedades que hay que configurar y viendo su nombre espero que se auto-expliquen, así mismas:
- URL donde se despliegan los archivos tipo CGI
- URL donde se despliegan el resto de archivos
- Path donde se copian el resto de archivos en entornos WSL
- Extensión de archivos CGI que se reconocen
- Directorio donde se ubicarán los archivos JavaScript
- Directorio donde se ubicarán los archivos CSS
- Directorio donde se ubicarán el resto de archivos
- Nombre de usuario de la conexión FTP
- Contraseña de la conexión FTP
El plugin es susceptible de importantes mejoras. Como por ejemplo, poder establecer distintas URL y credenciales dependiendo del proyecto. Hemos decidido no incluir esa funcionalidad porque cada usuario tendrá su propia preferencia. No obstante, si alguien se anima a hacerlo, encantado de echarle una mano para cualquier duda que pueda tener.
Os adelanto que sólo funciona con Xailer 9 ya que se apoya en alguna función que no existe más que en Xailer 9.
Podéis descargar el plugin de este enlace.
Un saludo y hasta pronto
Ignacio Ortiz de Zúñiga
[Equipo de Xailer]
Juanjo Navarro
Nueva edición del Technology Radar (la 30)
mayo 21, 2024 06:31
Si no conoces el Technology Radar de la empresa Thoughtworks, deberías echarle un vistazo.
Se trata de un informe semestral donde se analizan una serie de puntos (“blips” los llaman) sobre el mundo del desarrollo de proyectos tecnológicos.
Estos blips se dividen en cuatro tipos:
- Técnicas
- Herramientas
- Plataformas
- Lenguajes & Frameworks
Para cada blip te aconsejan:
- Adoptar
- Probar
- Evaluar – mantenerse al tanto y jugar un poco con él para conocerlo.
- Resistir – mejor no usarlo, es dudoso su futuro o utilidad.
Esta última edición (la 30) está llena de IA y devops, cómo no. Yo me suelo fijar en temas prácticos (en Herramientas o en Lenguajes y Frameworks, sobre todo).
Aquí os dejo lo que más me ha llamado la atención (y he probado más o menos) de la última edición:
- Pop – Herramienta para compartir la pantalla para hacer Pair Programming.
- Aider – Una IA que hace de “coworker” de programación y me ha parecido muy bien pensado.
- Continue – Un “Github Copilot” opensource en el que puedes elegir qué LLM utilizar (con el consiguiente coste por el uso del API si es de pago, claro). Puedes también utilizar un LLM local corriendo en tu infraestructura.
- Dify – Un creador “gráfico” de aplicaciones “LLM” bastante impresionante. Permite diseñar un “flujo” de trabajo, donde vas haciendo consultas a distintos modelos IA, unir la información, hacer otras llamadas dependiendo de la respuesta anterior, etc. Además tiene integrado un sistema RAG con lo que le puedes subir documentos que la IA utilizará como referencia.
- Crabviz – Utilidad para VSCode que genera un gráfico de llamadas entre clases.
- Electric – Librería y framework que permite crear aplicaciones móviles o webapps con una base de datos “local” (que se ejecuta en el propio móvil o la página) y que automáticamente se sincroniza con un PostgreSQL en el back.
- LiteLLM – Algo así como un “proxy” LLM. Permite configurar distintos LLM y acceder a ellos con un API común.
Una sinfonía en C#
Configurar Docker + HTTPS + nginx
mayo 21, 2024 12:00
“Introducción”
Cuando queremos probar algo en local (una aplicación web), dentro de un contenedor, no podemos utilizar https como desde Visual Studio o IIS. Si necesitamos sí o sí https, debemos configurar algunas cosas, como por ejemplo, un certificado autofirmado, nginx, etc. En este post vamos a detaler cómo hacerlo.
Pasos
Vamos a necesitar hacer un par de cosas, voy a detallar los pasos a seguir en una PC con Windows y una aplicación .NET Core, es que lo que yo uso.
Básicamente pondremos nuestra aplicación en un contenedor, configuraremos nginx para que haga de proxy y que además tenga https. Luego un docker compose que levante todo.
Crear certificado autofirmado
Para crear certificados autofirmados, podemos utilizar openssl. En Windows, podemos instalarlo desde aquí.
y ejecutar este comando:
localhost.conf
[req]
default_bits = 2048
default_keyfile = localhost.key
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_ca
[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Texas
localityName = Locality Name (eg, city)
localityName_default = Dallas
organizationName = Organization Name (eg, company)
organizationName_default = localhost
organizationalUnitName = organizationalunit
organizationalUnitName_default = Development
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = localhost
commonName_max = 64
[req_ext]
subjectAltName = @alt_names
[v3_ca]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -config localhost.conf -passin pass:12345678
Esto creará dos archivos, localhost.crt y localhost.key, estos archivos los usuaremos en nginx.
Ahora necesitamos registrar el certificado como confiable ya que es auto-firmado. (es decir, registrar en Windows como confiable)
En el Administrador de Certificados (certmgr.msc), puedes encontrar esta ubicación siguiendo estos pasos:
Abrimos el Administrador de Certificados.
- Para esto escribimos certmgr.msc en el diálogo Ejecutar (Win + R).
- En el Administrador de Certificados, expande el árbol de Certificados “Usuario Actual” en el panel izquierdo.
- Debajo de esto, expande la carpeta Autoridades de Certificación Raíz Confiables.
Hacemos clic en la carpeta Certificados bajo Autoridades de Certificación Raíz Confiables.
Esta es la ubicación equivalente a Cert:\CurrentUser\Root en PowerShell.
Luego
En el Administrador de Certificados (certlm.msc, Certificate Manager for local machine), puedes encontrar esta ubicación siguiendo estos pasos:
- Abre el Administrador de Certificados para la Máquina Local. Puedes hacer esto escribiendo certlm.msc en el diálogo Ejecutar (Win + R).
- En el Administrador de Certificados, expande el árbol Certificados (Computadora Local) en el panel izquierdo.
- Debajo de esto, expande la carpeta Personal.
- Haz clic en la carpeta Certificados bajo Personal.
Ahora nginx usará los archivos de certificado y clave para servir https. Y deberías estar bien.
Configurar nginx
Para esto simplemente vamos a crear un archivo de configuración para nginx, que será el siguiente:
nginx.conf
worker_processes 1;
events { worker_connections 1024; }
http {
sendfile on;
upstream web-api {
server api:80;
}
server {
listen 80;
server_name localhost;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/ssl/certs/localhost.crt;
ssl_certificate_key /etc/ssl/private/localhost.key;
location / {
proxy_pass http://web-api;
proxy_redirect off;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $server_name;
}
}
}
Le decimos a nginx que utilice el certificado y la clave que creamos antes, y que escuche en el puerto 443. y con el proxy_pass le decimos que redirija las peticiones al servicio que escucha en el puerto 80. (más adelante ese será el nombre del servicio en el docker compose)
Ahora creamos el Dockerfile para nginx:
FROM nginx:alpine
COPY ./nginx.conf /etc/nginx/nginx.conf
COPY localhost.crt /etc/ssl/certs/localhost.crt
COPY localhost.key /etc/ssl/private/localhost.key
CMD ["nginx", "-g", "daemon off;"]
Básicamente copiamos el archivo de configuración y los archivos de certificado y clave al contenedor.
Configurar nuestra app
En este caso una simple aplicación .NET Core, que escucha en el puerto 80.
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
ENV ASPNETCORE_HTTP_PORTS 80
EXPOSE 80
EXPOSE 443
COPY --from=build /app/out ./
CMD ["dotnet", "app.dll"]
Docker compose
version: "3.7"
services:
reverseproxy:
build:
context: ./nginx
dockerfile: Dockerfile.nginx
ports:
- "8080:80"
- "1443:443"
restart: always
api:
depends_on:
- reverseproxy
build:
context: .
dockerfile: Dockerfile
ports:
- "8088:80"
restart: always
Simplemente apuntamos los dos servicios a sus Dockerfiles, y abrimos el puerto 1443 para https.
Si vemos algún error en el navegador relacionado con https lo más probable es que no hayamos registrado el certificado como confiable.
Dejo por acá un repositorio con el código
Nos leemos.
Arragonán
El lado estratégico de Domain-Driven Design. CommitConf 2024
mayo 08, 2024 12:00
Hace unas semanas estuve en Commit Conf en Madrid, evento al que no iba desde hace mucho. Estuve compartiendo la charla El lado estratégico de Domain-Driven Design, iterando ligeramente la que hice hace unos meses en La Vertical, a su vez basada en una charla más larga (y espesa) que he impartido in-company en varias ocasiones.
En los últimos años ha crecido el interés y la adopción de Domain-Driven Design en la comunidad de desarrollo de software. Ahora es bastante habitual oír hablar del lado táctico de DDD, la mayoría de las veces acompañado del uso de ports & adapters (aka Hexagonal Architecture). Pero, al menos en castellano, no he visto hablar apenas de DDD estratégico y lo que nos puede aportar a nivel de Sociotechnical Architecture.
Así que de ahí vino buena parte de mi motivación de proponer repetirla en un evento mucho más masivo como es la Commit Conf.
La presentación está dividida en 4 bloques:
- Introducción a DDD y específicamente a la parte estratégica
- Resumen de las actividades estratégicas basado en el Domain-Driven Design Starter Modelling Process de DDD Crew
- Un ejemplo práctico de DDD estratégico basado en un caso real, mostrando su división y conexión entre dominios visibilizándolo con un Context Map un tanto enriquecido con su clasificación desde diferentes puntos de vista
- Otras consideraciones a tener a nivel de la organización de equipos
Aquí os dejo el vídeo de la charla
Y el genially que usé para la presentación
Meta-Info
¿Que es?
Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.
Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.
Idea: Juanjo Navarro
Diseño: Albin
Fuentes
- Arragonán
- Bitácora de Javier Gutiérrez Chamorro (Guti)
- Blog Bitix
- Blog de Diego Gómez Deck
- Blog de Federico Varela
- Blog de Julio César Pérez Arques
- Bloggingg
- Buayacorp
- Coding Potions
- DGG
- Es intuitivo...
- Fixed Buffer
- Header Files
- IOKode
- Infectogroovalistic
- Ingenieria de Software / Software Engineering / Project Management / Business Process Management
- Juanjo Navarro
- Koalite
- La luna ilumina por igual a culpables e inocentes
- Made In Flex
- Mal Código
- Mascando Bits
- Metodologías ágiles. De lo racional a la inspiración.
- Navegapolis
- PHP Senior
- Pensamientos ágiles
- Picando Código
- Poesía Binaria
- Preparando SCJP
- Pwned's blog - Desarrollo de Tecnologia
- Rubí Sobre Rieles
- Spejman's Blog
- Thefull
- USANDO C# (C SHARP)
- Una sinfonía en C#
- Variable not found
- Yet Another Programming Weblog
- design-nation.blog/es
- info.xailer.com
- proyectos Ágiles
- psé
- vnsjava