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.

Navidrome

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 😆

Tempo con Navidrome

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:

Navidrome - página de opciones personales

Navidrome - página de opciones personales

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.

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

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

Imagen decorativa de la barra de tareas de Windows

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:

"C:\Program Files\Google\Chrome\Application\chrome_proxy.exe" --profile-directory=Default --app-id=fmgjjmmmlfnkbppncabfkddbjimcfncm

Propiedades del acceso directo a Gmail en la barra de tareas

Pues bien, lo que hay que hacer es simplemente añadirle al final (separando con un espacio del contenido previo) el siguiente texto:

--app-launch-url-for-shortcuts-menu-item="https://mail.google.com/?authuser=juanlopez1987@gmail.com"

El valor de Destino por tanto quedaría así:

"C:\Program Files\Google\Chrome\Application\chrome_proxy.exe" --profile-directory=Default --app-id=fmgjjmmmlfnkbppncabfkddbjimcfncm --app-launch-url-for-shortcuts-menu-item="https://mail.google.com/?authuser=juanlopez1987@gmail.com"

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.

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

Variable not found

Enlaces interesantes 588

diciembre 02, 2024 07:05

Representación de un millón de tareas ejecutándose concurrentemente

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...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI / Mobile

Otros

Publicado en Variable not found.

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

Picando Código

Razones para usar RSS

noviembre 27, 2024 11:30

RSS

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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!

Feed RSS de Picando Código

El post Razones para usar RSS fue publicado originalmente en Picando Código.

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

Variable not found

El código fuente de .NET muy a mano: source.dot.net

noviembre 26, 2024 07:05

Página principal de source.dot.net

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

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

Variable not found

Enlaces interesantes 587

noviembre 25, 2024 07:05

Enlaces interesantes

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...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Otros

Publicado en Variable not found.

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

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:

{ "nombre": "Fernando" } => { nombre: "Fernando" }

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:

"\([a-z_]+\)":

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.

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

Variable not found

Los nuevos métodos LINQ en .NET 9: CountBy(), AggregateBy() e Index()

noviembre 19, 2024 07:05

Nuevos métodos LINQ en .NET 9

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.

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

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.

Cómics Transformers

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.

Comics Transformers - 1 al 12

Comics Transformers - 1 al 12

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. 

Optimus PrimeLa 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:

Transformers - You got the touch...

Al llegar a este panel hay que detener la lectura y reproducir en nuestro reproductor de música favorito la canción "The Touch" de Stan Bush para seguir leyendo.

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.

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

Variable not found

Enlaces interesantes 586

noviembre 18, 2024 07:05

Alan Turing echándose las manos a la cabeza

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...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI / Xamarin

Otros

Publicado en Variable not found.

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

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:

PHP Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in wp-content/plugins/wp-syntax/wp-syntax.php on line 380

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:

LANGS = Rouge::Lexer.all.sort_by(&:tag).map do |lexer|
  [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:

SELECT * FROM `wp_posts`
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:

SELECT * FROM `wp_comments` WHERE comment_content LIKE "%pre lang%";

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.

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

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:

XBox Guide + XBox RT

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:

Steam - XBox Controller

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.

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

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.

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

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.

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

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"

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

info.xailer.com

xaWeb

octubre 15, 2024 07:20

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.

xaWeb: All samples

Comentarios abiertos para conocer vuestras opiniones y sugerencias. Gracias por vuestro tiempo.

Un cordial saludo

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

Metodologías ágiles. De lo racional a la inspiración.

Scrum master a tiempo completo: 42 Tareas

octubre 04, 2024 08:29

Uno de los artículos que más referencio en mi formación en Scrum cuando hablo de las labores del Scrum Master es:&nbsp;42-tasks-for-a-scrum-masters-job. Por alguna razón, todo el mundo parece entender que el Product Owner es un trabajo a tiempo completo, o ser miembro de un equipo también, pero que probablemente el rol del Scrum Master puede ser realizado a media jornada o incluso menos. El scrum

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

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.

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

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.
SAI_BadgeSizes_DigitalBadging_CSM
  • 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:

 ✍ Para inscripciones, consultar la página oficial del Máster.

A continuación, más detalle acerca del Postgrado en Agile (PMA) y del Máster en Agile (MMA)

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.
AsignaturasTemasProfesores
Fundamentos & InceptionEquipos 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é

Agustín Yagüe

Scrum y KanbanEstimación y planificación ágil, framework de Scrum, retrospectivas, Kanban, métricas ágiles, herramientas ágiles físicas, radiadores de información.Raul Herranz

 

Teodora Bozheva

Personas y equiposGestión de personas, gestión de conflictos, motivación e incentivos, facilitación compartida, contratación ágil.

 

Visual thinking.

Steven Wallace

 

Silvia Sistaré

Virginia Armas

Gestión de producto ágilDesign Thinking, Lean UX & Prototyping.

 Estrategia de Producto – Consciencia situacional (Wardley Maps), modelo de negocio (Lean Canvas), modelo de tracción, métricas AARRR.
Planificación y gestión estratégica – OKR y Hoshin Kanri.

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 PostgradoDurante 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:

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):

AsignaturasTemasProfesores
Enterprise Learning & personal efficiencyAgile Kaizen, Comunidades de Práctica, Open Spaces, Talent development, gamification.

 

Productividad y aprendizaje personal en Agile (eficiencia).
Steven Wallace


Esther Somoza
Lean Thinking & Agile ManagementLean. Escalado con Kanban.

 

Business Agility con ViMa – agilidad para equipos de negocio

Agile-Lean Management

Teodora Bozheva

  Xavier Quesada


Xavier Albaladejo

Coaching y CulturaCoaching de equipos, creación de equipos de alto rendimiento, liderazgo.

 

Tipos de cultura empresarial, transformación cultural.

Joserra Díaz

 

Jasmina Nikolic
Jaume Gurt

Transformación ContinuaEstrategia 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

 

Mattijas Larsson

Trabajo Final de MásterDurante 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).

 ✍ Para más detalles e inscripciones, consultar la página oficial del Máster.

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

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.

Continuar leyendo en Blog Bitix

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

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.

Benchmark std::string

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.

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

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]

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

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.

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

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.

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

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.

Foto de la sala de conferencias del track 1 del evento

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

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

Meta-Info

¿Que es?

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

rss subscripción

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

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

Idea: Juanjo Navarro

Diseño: Albin