Picando Código

Generar un enlace automático para compartir posts en un canal de Telegram

diciembre 29, 2025 09:00

Ruby TelegramLos posts de Picando Código se comparten automáticamente en un canal de Telegram ni bien se publican. Esto se hace mediante una función PHP en el archivo functions.php de mi tema de WordPress. Escribí al respecto en Actualiza un canal en Telegram automáticamente desde WordPress.

El canal es relativamente popular, al momento de escribir esto cuenta con 89 miembros (91 contándome a mí y al bot que publica los posts). El código viene funcionando lo más bien desde 2018. La función genera una dirección web con los datos necesarios y hace un request a esa URL.

La semana pasada, la publicación automática no funcionó al publicarse un post. Así que fui a fijarme en el log de errores de mi servidor, y me encontré con el siguiente mensaje:

[26-Dec-2025 09:31:03 UTC] PHP Warning: file_get_contents(https://api.telegram.org/bot[API_TOKEN]/sendMessage?chat_id=%40picandocodigo&text=https%3A%2F%2Fpicandocodigo.net%2F2025%2Frecomendaciones-de-podcasts-2%2F): Failed to open stream: Connection timed out in .../wp-content/themes/picandocodigo7/functions.php on line 42

Hubo un timeout en la conexión, esto puede pasar por muchas razones: problemas en la red, el servidor está sobrecargado, o estuvo caído por un tiempo determinado.

Debería capturar este error en mi código y agendar un reintento, pero no sé si vale la pena tanta complejidad. El pedido HTTP que se hace a la API de Telegram para compartir los posts en el canal es relativamente simple. Usa el método GET, así que se puede hacer desde cualquier navegador web (o curl, o cualquier herramienta que pueda hacer un pedido HTTP). Así que me escribí un código Ruby que genera la URL que necesito para compartir el enlace en el canal de Telegram.

El código:

require 'cgi'
require 'uri'

def uso
  puts <<~MSG
  Uso:

  #{__FILE__} link

  E.g.

  #{__FILE__} https://picandocodigo.net

  MSG
end

if ARGV.empty?
  uso
  abort 'Es necesario pasar un link como parámetro'
end

link = ARGV[0]

unless link =~ URI::DEFAULT_PARSER.make_regexp
  uso
  abort 'El URL no es válido'
end

api_token = File.read(File.expand_path('./.telegram_api_token'))
chat_id = '@picandocodigo'

url = "https://api.telegram.org/bot#{api_token}/sendMessage?chat_id=#{chat_id}&text=#{CGI.escape(link)}"
puts url

La función uso explica cómo usar el script. Tenemos que ejecutarlo con un argumento que es la URL que queremos compartir. Se muestra cuando no pasamos ningún argumento o el argumento no es una URL válida. El id del chat está hardcodeado a @picandocodigo, pero se podría usar cualquier otro. Lee el token para usar la API de Telegram desde un archivo .telegram_api_token en el mismo directorio. Finalmente arma el String final de la url escapando los caracteres del url que pasamos como argumento con CGI.escape.

La ejecuté y obtuve la URL, hice clic directamente en la consola y el post se compartió en el canal de Telegram de Picando Código:

ruby request-telegram.rb https://picandocodigo.net/2025/recomendaciones-de-podcasts-2/
> https://api.telegram.org/bot[API_KEY]/sendMessage?chat_id=@picandocodigo&text=https%3A%2F%2Fpicandocodigo.net%2F2025%2Frecomendaciones-de-podcasts-2%2F

Es la primera vez que tengo que hacer esto a mano desde que dejé andando la automatización. Pero si por alguna razón vuelve a pasar, tengo este script para solucionarlo rápido.

El post Generar un enlace automático para compartir posts en un canal de Telegram fue publicado originalmente en Picando Código.

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

Picando Código

Recomendaciones de Podcasts

diciembre 26, 2025 09:00

Recomendaciones de podcasts

Desde hace un tiempo he cambiado bastante mi postura respecto a los podcasts. En mi primer post sobre podcasts en 2020, decía que no escuchaba podcasts. Y lo cierto es que no había encontrado podcasts que me interesaran (excepto Sonido Bragueta, de . Sigo escuchando Sonido Bragueta... ¡escuchen Sonido Bragueta!). Hoy en día sigo algunos podcasts más, que me resultan muy interesantes y entretenidos.

Y está bueno, eso de evolucionar y cambiar de opinión. Que al final si uno se queda siempre en la misma, nos perdemos de un montón de cosas. Como dijo Bill Stevenson, legendario baterista de Descendents, en uno de los podcasts que escuché: "Si no estás avergonzado de lo que hiciste cuando eras joven, no has crecido como persona". O algo así, ni siquiera me acuerdo exactamente la frase, y él mismo estaba parafraseando a alguien más. Pero se entiende la idea (espero).

Hoy en día veo a los podcasts como veía a la radio en otros tiempos. Sigo escuchando radio también, tanto online como en mi transmisor analógico de radio que tiene una perilla para sintonizar las estaciones. Así que lo podcasts no la han reemplazado, sino que complementan lo que escucho además de radio y música. Mantengo el tema de que no puedo trabajar y escuchar podcasts a la vez. O me concentro en lo que estoy haciendo del trabajo o en el podcast. Si escucho algo en el trabajo generalmente es música (tanto en la radio como mi música), como de compañía. Pero no me sale prestar atención a un podcast mientras trabajo, programo o escribo para cosas mías.

Las veces que escucho podcasts, lo hago desde mi teléfono. Caminando por la calle siempre uso mis auriculares. Callejeo bastante, camino a todos lados, y me molesta mucho el ruido del tránsito y demás. Lo que tiene vivir en una ciudad con tanta gente y tanto movimiento. Ni que hablar que las ambulancias de Edimburgo son una amenaza, tienen la sirena más alta que he oído en mi vida, capaces de dejar a uno sordo. Otra amenaza son los potenciales infartos cuando vas caminando y empieza una sirena de golpe al lado tuyo...

Software para podcasts

En cuanto a software, para los que están basados en YouTube (como Sonido Bragueta, espero que ya hayan escuchado Sonido Bragueta a esta altura), uso NewPipe. NewPipe es genial para interactuar con YouTube. No tengo la aplicación de YouTube en mi teléfono, sólo uso NewPipe:

NewPipe fue creado con el propósito de obtener la experiencia original de YouTube en tu smartphone sin anuncions molestos o permisos cuestionables.

Es intuitiva, llena de características útiles, respeta la privacidad de sus usuarios y es software libre bajo licencia GPLv3. Aparte te permite bloquear el teléfono y dejar ejecutando un video (aunque sea sólo audio) de YouTube. Hasta donde llegué a usar la aplicación oficial de YouTube, no permitía hacer esto. Y muy importante también es que bloquea los malditos anuncios de YouTube.

Para los que son podcasts más "tradicionales" uso AntennaPod. Es una aplicación para escuchar podcasts y suscribirse a feeds RSS, también software libre bajo licencia GPLv3. No tiene intereses comerciales y respeta nuestra privacidad. Está bueno porque las veces que me enteré de algún podcast que podía interesarme, lo busqué directamente en AntennaPod y lo agregué a mis suscripciones desde ahí mismo.

Ambos programas están disponibles a través de F-Droid en Android: el catálogo instalable de aplicaciones FOSS (software libre y de código abierto, en inglés) para la plataforma Android.

Video Game History Hour

De los podcasts que más disfruto y más he escuchado en 2025. Video Game History Hour es el podcast de la Video Game History Foundation. [link de suscripción]

Usé material de la fundación en mi artículo Nintendo en América Latina en la década de los 90 - piratería y Famicom :

Recientemente The Video Game History Foundation abrió al público el acceso digital a su biblioteca. La fundación es una organización sin fines de lucro dedicada a preservar, celebrar y enseñar la historia de los videojuegos. Entre sus proyectos se encuentra la preservación del código fuente de juegos, educación, archivo de arte e información, recuperación y restauración.

El podcast está actualmente integrado por Frank Cifaldi fundador y director de la fundación, Robin Kunimune productora del podcast y más en la fundación y Phil Salvador, director de la biblioteca. En sus comienzos entrevistaban a una persona invitada denominada experta en algún tema en particular relacionado a la historia de los videojuegos. Ya sea porque investigaron un tema o porque lo vivieron. Me encanta escuchar o leer este tipo de entrevistas, y aprender y conocer anécdotas y curiosidades de distintos aspectos del mundo de los videojuegos y su historia. Increíblemente interesante.

En los capítulos más recientes también hablan del trabajo de la fundación, y han ido presentando personalmente a los integrantes, lo cual también me resulta muy interesante. Dato curioso al azar: la protoconsola de Nintendo que terminó siendo el Famicom, usaba como controles consolas Game & Watch hackeadas para conectarse y usar sus controles. Y así como ese hay muchos más. Van 145 episodios al momento de escribir esto, así que hay un montón de material para escuchar y entretenerse.

No sé el orden exacto del resto de los podcasts porque la referencia que tengo es mi año según AntennaPod:

Antennapod Echo

Resumen del 2025 en AntennaPod. Qué lindo ver el mensaje "generado de manera privada en tu teléfono", algo cada vez menos común.

Pero estoy seguro que en el top 5 deberían estar Sonido Bragueta y el siguiente podcast a recomendar:

The Atari Podcast

No tengo nostalgia por el Atari de los 80's, llegué tarde para ser de la generación que creció con un Atari 2600. Pero reconozco su legado y admiro mucho al Atari moderno. Han hecho un muy buen trabajo con los relanzamientos de sus consolas, con mucho respeto a lo que vino antes. Pero más que nada vienen destacando en cuanto a desarrollo. Por un lado han revivido y reinventado conceptos de los juegos clásicos de aquellas épocas. Por otro trabajan en desarrollos nuevos también han adquirido un par de estudios cuyo trabajo admiro y disfruto mucho: Nigthdive Studios y Digital Eclipse. Ambos estudios combinan lo retro con lo moderno en un balance ideal.

El trabajo de Digital Eclipse con su Golden Master Series es increíble. Implementaron un formato documental interactivo que le agregan contexto a cada juego, lo que amplifica la experiencia de jugarlos. Totalmente recomendable, y mientras sigan sacando de éstos títulos, los seguiré obteniendo. El año pasado también publicaron un título original Mighty Morphin Power Rangers: Rita's Rewind. Un excelente beat 'em up que captura el sentimiento de alquilar un juego nuevo de Super Nintendo un fin de semana y sentarse a jugarlo con un amigo.

Nightdive Studios también trabaja con lo retro, portando y desarrollando para plataformas modernas juegos que consideran "tesoros perdidos". Su trabajo incluye restauración y tienen una reputación por las mejoras que actualizan estos clásicos y los hacen disponibles en todas las plataformas modernas. También han desarrollado y publicado títulos propios manteniendo un estilo clásico.

Y si bien menciono no tener nostalgia por los videojuegos de Atari de los 80's, disfruté muchísimo Atari 50: the Anniversary Celebration. El primer título del formato que se convirtió en Golden Master Series de Digital Eclipse. Aprender de la historia y evolución de Atari e ir jugando los juegos cronológicamente en paralelo con el documental interactivo los hace apreciar mucho más que simplemente jugarlos de una colección.

El podcast está a cargo de Jason Polansky, Director Asociado de Juegos. Jason invita a desarrolladores tanto de los estudios de Atari, como de terceros trabajando en títulos publicados por Atari y demás. También somete a los invitados a algunos juegos basados en trivia que resultan entretenidos.

El podcast está disponible en YouTube, link de AntennaPod y feed.

Chris DeMakes A Podcast

El anfitrión es Chris DeMakes, cantante, guitarrista y escritor de canciones en la famosa banda de skapunk que voy a tener el gusto de ver en vivo en marzo en Glasgow: Less Than Jake. Me encanta la música, y tengo una afición muy especial por el punk rock, ska punk, hardcore melódico y demás sub-géneros del Punk. El podcast generalmente se concentra en analizar una canción en particular invitando a alguno de los artistas involucrados en su creación y desarrollo.

Entre los invitados han estado los legendarios Descendents: Milo Aukerman, Bill Stevenson, Stephen Egerton y Karl Alvarez, así como Chad Price de ALL. Brian Baker y Brett Gurewitz de la mejor banda del universo, Bad Religion. Otros invitados de lujo incluyen a Aaron Barrett y Scott Klopfenstein de Reel Big Fish (¡juntos!), su compañero de banda Roger Lima, John Feldmann de Goldfinger, Joey Cape de Lagwagon, Angelo Moore de Fishbone, Stacey Dee de Bad Cop Bad Cop, Nikola Šarčević de Millencolin, Ray Carlisle de Teenage Bottlerocket... Y estos son sólo algunos de los nombres de las bandas que más me gustan, hay casi 300 episodios para escuchar. A veces también conversa con su productor de canciones y artistas en particular, como Zombie y Dolores O'Riordan de The Cranberries.

Me encanta este podcast porque Chris DeMakes es no sólo protagonista de la escena a la que celebra y difunde, también es muy nerd con las canciones. Analiza de forma relativamente técnica las canciones compás por compás junto al artista invitado. Es divertido cuando le hace alguna pregunta técnica de composición al entrevistado, y éste responde "no tengo ni idea". En muchos casos simplemente hacen algo "porque suena bien", y así sale.

Este estilo de música y gran parte de las bandas que invita -a pesar de su legado y popularidad- son un poco nicho. No reciben tanta atención masiva, y no conozco muchos medios que le den este tipo de difusión. Así que disfruto mucho de escuchar a los artistas, las anécdotas y detalles de la producción de música que tanto disfruto. Chris DeMakes es un nerd del mismo estilo de música que me gusta a mí, nerdeando con la gente que crea esa música, excelente.

El podcast está disponible en YouTube, link de AntennaPod y feed.

Historic Scotland Podcast

Soy miembro de Historic Scotland, una organización pública a cargo de investigar, cuidar, mantener y promover el ambiente histórico de Escocia. Mantienen colecciones históricas así como edificios y estructuras (castillos, monasterios, museos, etc.). Además de producir información de eventos históricos y noticias sobre su trabajo, hace poco empezaron a publicar un podcast. La primera temporada cuenta con 8 episodios, y hay una segunda temporada ya anunciada. En algún lado dice algo así como que el podcast es "exclusivo para miembros", pero está disponible públicamente.

Además de aprender un poco más de historia, inspira a encontrar potenciales lugares a visitar. Tomo éstas cosas como punto de partida, y de ahí planeo un paseo a alguna parte de Escocia que todavía no conozco. De repente un poco específico porque vivo acá, pero puede interesarle a más gente que tenga interés en Escocia y su historia.

El feed del podcast de Historic Scotland.

Coffee Break Gaelic

Este es otro podcast bastante específico. Desde hace unos años empecé a estudiar Gaélico Escocés. Hice unos cuantos cursos en la Universidad de Edimburgo, he ido a varios eventos, mirado novelas en Gaélico, leído bastante, y pasé muchas horas en el curso de Duolingo. Pero todavía me falta muchísimo para poder decir que sé Gaélico. Los podcasts Coffee Break son bastante populares para aprender idiomas, me los recomendó mucha gente distinta en distintos ambientes.

En este podcast Mark, un aprendiz de idomas, conversa y aprende Gaélico desde cero con Susanna, profesora de Gaélico Escocés. Lo empecé a escuchar bastante después de haber empezado a estudiar, así que los primeros episodios me resultan super básicos. Pero es un buen recurso para repasar. Lo recomiendo como extra si están aprendiendo un idioma distinto, hay para Alemán, Italiano, Chino, Sueco, Japonés e incluso uno de Español a Inglés.

Enlace de AntennaPod y feed.

Párrafos finales a modo de conclusión o algo... (para mantener la cohesión con el uso de títulos)

Es interesante rever lo que escribí en 2020:

Otro tema que me juega en contra de los podcasts, son muy largos. Me interesaría escuchar un podcast si incluye algo de información que no puedo leer en ningún lado, o una opinión o punto de vista de alguien cuya opinión o punto de vista respeto/admiro o me importa por alguna razón. Pero muchos podcasts dan un montón de vueltas para decir algo, como esas reuniones que podrían haber sido un email. En parte volvemos a párrafo anterior donde despotrico contra los podcasts y YouTube cual viejo gruñón.

Y el tema es que no había encontrado podcasts buenos. Sí había tenido experiencia con algunos que eran básicamente 2 o 3 personas sin nada muy interesante para decir que grababan una conversación larga con un mínimo hilo conductor. Pero cuando se trata de algo entretenido, gente interesante y/o divertida, el tiempo se pasa volando. Como decía, escucho los podcasts mientras camino pero también haciendo tareas que no requieren absoluta concentración, las hacen más llevaderas. Ahora que encontré podcasts que me gustan, me resulta tal cual un equivalente a escuchar radio.

Si bien, como decía, escucho algo casi todo el tiempo cuando ando por la calle, hay excepciones. Cuando camino por un parque o un lugar con muchos árboles o naturaleza, me quito los auriculares. En Edimburgo hay bastantes caminos y parques lejos del tránsito que son ideales para escuchar pájaros, agua corriendo y demás sonidos naturales. ¡Lo recomiendo!

También hay un ejercicio mental extra que hago a veces gracias a los podcasts. No pasa seguido, pero si un capítulo en particular me aburre o no me engancha, me desconecto completamente y mi cerebro empieza a divagar y pensar en otras cosas. Y es un buen ejercicio, "aburrirse" y reflexionar, imaginar, y demás procesos creativos por los que pasa el cerebro cuando no está comprometido con una actividad. Como dijo Satoru Iwata: "El tiempo que pasas pensando en cosas totalmente aleatorias nunca es tiempo perdido".

Pero en fín, esos son los podcasts que vengo escuchando recientemente. Si tienen alguna recomendación, pueden dejarla en los comentarios, ¡gracias!

El post Recomendaciones de Podcasts fue publicado originalmente en Picando Código.

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

Navegapolis

Spec-Driven Development

diciembre 24, 2025 08:53

El contexto: los problemas del vibe coding

Para entender Spec-Driven Developmen (SDD) o, hablando en nuestro idioma: desarrollo guiado por especificaciones, es bueno empezar conociendo el problema que intenta solucionar.
En febrero de 2025, Andrej Karpathy (cofundador de OpenAI y exdirector de IA en Tesla) acuñó el término vibe coding en un tweet que se hizo viral(1)

«Hay un nuevo tipo de programación que llamo ‘vibe coding’, donde te dejas llevar completamente por las vibraciones, abrazas los exponenciales, y olvidas que el código siquiera existe. […] Acepto todo siempre, ya no leo los diffs. Cuando recibo mensajes de error, simplemente los copio y pego sin comentarios, y normalmente eso lo arregla.»

Para proyectos de fin de semana o prototipos rápidos, dejarse llevar por la IA puede funcionar, pero tiene limitaciones: código aparentemente correcto, pero con bugs sutiles, arquitecturas inconsistentes, vulnerabilidades de seguridad, y la incomodidad de no conocer la lógica que implementa el código generado.

Los datos son reveladores: según Y Combinator, el 25% de las startups de su cohorte de invierno 2025 tenían bases de código generadas en un 95% por IA(2). Es impresionante, pero: ¿quién entiende y mantiene ese código?

Qué es Spec Driven Development

Spec Driven Development es, en esencia, un enfoque en el que la especificación precede y guía al código. No es un framework ni una metodología prescriptiva como scrum. Es una filosofía de trabajo que propone:

  1. Escribir primero una especificación clara de lo que se desea construir: objetivos, reglas de negocio, criterios de aceptación, restricciones técnicas.
  2. Usar esa especificación como fuente tanto para humanos como para agentes de IA.
  3. Generar código a partir de la spec, no de prompts improvisados.

Como lo resume GitHub en su documentación de Spec Kit: «En este nuevo mundo, mantener software significa evolucionar especificaciones. […] El código es el enfoque de última milla.»(3)

Los tres niveles de SDD

Birgitta Böckeler, de Thoughtworks, propone una taxonomía útil para entender las diferentes implementaciones(4):

  • Spec-first: Escribes la spec antes de codificar, la usas para la tarea en curso, y luego la descartas. Es el nivel más básico.
  • Spec-anchored: La spec se mantiene después de completar la tarea y se usa para evolución y mantenimiento del feature.
  • Spec-as-source: La spec es el artefacto principal. Solo editas la spec, nunca tocas el código directamente. El código se regenera desde la especificación.

La mayoría de herramientas actuales operan en el nivel spec-first, algunas aspiran a spec-anchored, y solo unas pocas experimentan con spec-as-source (como Tessl Framework).

La relación con IA: el catalizador del resurgimiento

Aunque la idea de «especificar antes de codificar» está en el origen de la ingeniería de software, SDD ha resurgido ahora por una razón específica: los LLMs necesitan contexto estructurado para generar código coherente.

Piénsalo así: cuando le das a un agente de código un prompt vago como «hazme un login», está adivinando arquitectura, patrones, validaciones y flujos de error. Cuando le das una especificación detallada que define exactamente qué debe pasar, el código resultante tiene muchas más probabilidades de hacer lo que necesitas.

La spec funciona como un «super-prompt» persistente y versionable. Como describe el equipo de Kiro (AWS): «Una especificación es una especie de super-prompt (versionado, legible por humanos).»(5)

Herramientas del ecosistema

El ecosistema de herramientas SDD está creciendo rápidamente(6):

  • GitHub Spec Kit: Toolkit open source que proporciona un flujo estructurado: Constitution → Specify → Plan → Tasks → Implement. Funciona con Copilot, Claude Code y otros.
  • Kiro (AWS): IDE basado en VS Code con flujo integrado de Requirements → Design → Tasks.
  • Tessl Framework: Explora el nivel spec-as-source con mapeo 1:1 entre specs y archivos de código.
  • BMAD Method: Usa agentes virtuales (Analyst, Product Manager, Architect) para generar PRDs y specs de arquitectura.

SDD, TDD y BDD: primos cercanos, no competidores

Si trabajas con metodologías ágiles, probablemente te preguntarás cómo encaja SDD con prácticas que ya conoces. La buena noticia: no son excluyentes, son complementarias(7).

  • TDD (Test Driven Development): Tests primero. Escribes un test que falla, luego el código para pasarlo. Excelente para calidad a nivel de unidad, pero no captura el intent de producto completo.
  • BDD (Behavior Driven Development): Comportamiento primero. Escenarios en formato Given-When-Then que describen cómo se comporta el sistema. Fuerte para alineación con stakeholders, pero deja decisiones técnicas abiertas.
  • SDD (Spec Driven Development): Especificación primero. Define el qué y el por qué, añade un plan técnico, y descompone en tareas. La spec es el ancla que mantiene a todos (humanos y agentes) alineados.

En la práctica, puedes usar SDD para definir el feature completo, TDD para cada tarea individual, y BDD para validaciones end-to-end. Como dice Beam.ai: «SDD te dice qué y por qué. BDD verifica comportamiento en todo el sistema. TDD asegura corrección a nivel de código. Estas prácticas funcionan bien juntas.»

La tensión con Agile (y cómo resolverla)

La pregunta incómoda surge porque el Manifiesto Ágil dice «software funcionando sobre documentación extensiva», y esto contradice SDD ese principio al pedir especificaciones detalladas.

La respuesta corta es que depende de cómo lo implementes; y la respuesta larga es que SDD no propone documentación extensiva estilo waterfall. Propone especificaciones vivas, ejecutables y versionadas que evolucionan con el código. Como GitHub lo describe: «Spec-Driven Development no se trata de escribir documentos de requisitos exhaustivos que nadie lee. Tampoco se trata de planificación waterfall.» (3)

En la práctica, SDD funciona bien a nivel de feature o sprint. No estás especificando todo el producto de antemano; estás especificando la siguiente funcionalidad con suficiente detalle para que un agente de IA pueda implementarla correctamente.

Consideraciones críticas y limitaciones

Pero SDD puede no ser una bala de plata. Estos son los puntos de crítica más relevantes en la comunidad profesional:

El problema humano

Como señala Daniel Sogl en DEV Community: «El problema principal no es la IA, es el factor humano. SDD requiere que los desarrolladores especifiquen sus intenciones con precisión. […] Después de más de 10 años en desarrollo de software, rara vez he experimentado proyectos donde los requisitos estuvieran completamente formulados antes de la implementación.»(8)

Escribir buenas specs es difícil. Requiere claridad de pensamiento, conocimiento del dominio, y la disciplina de pensar antes de actuar.

Overhead vs. beneficio

Birgitta Böckeler de Thoughtworks probó varias herramientas SDD y encontró que para tareas pequeñas, el proceso era desproporcionado: «Cuando pedí a Kiro que arreglara un pequeño bug, el documento de requisitos lo convirtió en 4 ‘user stories’ con 16 criterios de aceptación […] Era como usar un mazo para romper una nuez.»(4)

SDD tiene más sentido para features medianos a grandes donde la inversión upfront se amortiza en menos correcciones posteriores.

Falsa sensación de control

Las ventanas de contexto son más grandes, pero eso no significa que la IA siga todas las instrucciones. Böckeler observó: «Frecuentemente vi al agente no seguir todas las instrucciones. […] También vi al agente excederse porque seguía instrucciones demasiado ávidamente.»(4)

Las specs ayudan, pero no eliminan el no-determinismo de los LLMs. Todavía necesitas revisar y validar.

¿Revisar markdown o código?

Algunas herramientas generan cantidades masivas de archivos markdown. Como comenta Böckeler: «Honestamente, preferiría revisar código que todos estos archivos markdown. […] Eran repetitivos y tediosos de revisar.»(4)

Una buena herramienta SDD debería proporcionar una experiencia de revisión de specs genuinamente mejor que revisar código, no peor.

Entonces, ¿merece la pena?

Como con cualquier práctica emergente, la respuesta honesta es: depende.

SDD probablemente te beneficie si:

  • Trabajas regularmente con agentes de código IA
  • Tus proyectos tienen complejidad media-alta
  • Valoras la trazabilidad y la documentación viva
  • Tu equipo puede invertir tiempo en aprender un nuevo flujo de trabajo

Probablemente no lo necesites si:

  • Solo haces prototipos rápidos o proyectos personales
  • Tu trabajo consiste principalmente en fixes pequeños y mantenimiento
  • Prefieres un control directo y granular sobre cada línea de código

Si decides probarlo, el consejo del equipo de AI Native Dev es pragmático: «Empieza con un feature. No especifiques toda tu aplicación. Elige una funcionalidad bien entendida y escribe una spec detallada. Ve cómo rinde tu agente de IA.»(9)

Como resume el equipo de AI Native Dev: «Estamos todos descubriendo esto juntos, y los patrones que emerjan vendrán de experiencias compartidas entre cientos de equipos.»(9)

Fuentes citadas

[1]: Andrej Karpathy en X (Twitter), 2 de febrero de 2025: x.com/karpathy/status/1886192184808149383
[2]: «Vibe coding» – Wikipedia. Datos de Y Combinator: es.wikipedia.org/wiki/Vibe_coding
[3]: GitHub Blog – Spec-driven development with AI: github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai
[4]: Birgitta Böckeler, Thoughtworks – Understanding Spec-Driven-Development: Kiro, spec-kit, and Tessl: martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html
[5]: Kiro – The future of AI spec-driven software development: kiro.dev/blog/kiro-and-the-future-of-software-development
[6]: Microsoft for Developers – Diving Into Spec-Driven Development With GitHub Spec Kit: developer.microsoft.com/blog/spec-driven-development-spec-kit
[7]: Beam.ai – Spec Driven Development: The Future of Building with AI: beam.ai/agentic-insights/spec-driven-development
[8]: Daniel Sogl – Spec Driven Development: A initial review, DEV Community: dev.to/danielsogl/spec-driven-development-sdd-a-initial-review-2llp
[9]: AI Native Dev – Spec-Driven Development: 10 things you need to know about specs: ainativedev.io/news/spec-driven-development-10-things-you-need-to-know-about-specs

La entrada Spec-Driven Development se publicó primero en Navegápolis.

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

Picando Código

Metroid Prime 4: Beyond - Nintendo Switch 2

diciembre 23, 2025 10:51

Tras una espera de 8 años, el 4 de diciembre de 2025 se publicó Metroid Prime 4: Beyond para Nintendo Switch y Nintendo Switch 2. Es un juego muy entretenido, con gráficos y mundos espectaculares. Intenta cosas nuevas con resultados variables, pero no se aleja mucho de la fórmula que define a Metroid Prime.

Metroid Prime 4: Beyond

Metroid Prime 4: Beyond - Fury Green

Es la primera entrega de la serie después de Metroid Prime 3: Corruption en 2007. Metroid Prime 4 fue anunciado originalmente en el E3 de 2017 para Nintendo Switch. Sería el primer título no desarrollado por Retro Studios, sino por Bandai Namco. Dos años más tarde, Nintendo anunció que se había reiniciado el desarrollo desde cero, esta vez a cargo de Retro Studios otra vez. El trabajo del estudio anterior no había alcanzado los estándares impuestos por Nintendo.

Por un lado el optimismo de que Nintendo quería que esta fuera una entrega a la altura de las anteriores. Pero la noticia desalentaba un poco por la demora extra y cómo afectaría a su desarrollo general. Como se le atribuye a Shigeru Miyamoto: "Un juego demorado es eventualmente bueno, pero un juego sacado a las apuradas es malo para siempre" (esto antes que existieran los parches por internet).

Pasaron muchos años más en los que en cada presentación de Nintendo esperaba noticias de Metroid Prime 4. Entre medio disfruté de Metroid Dread y Metroid Prime: Remastered en Nintendo Switch. Hasta que finalmente en 2024 anunciaron el título Beyond y mostraron las primeras imágenes. Miré algún tráiler más, pero no quise averiguar mucho antes de jugarlo. Tampoco leí reseñas porque quería ir con la cabeza fresca y sin estar pre-dispuesto a nada.

Finalmente, llegó la versión física Metroid Prime 4: Beyond Nintendo Switch 2 Edition a mi puerta. De destacar que el cartucho rojo para Nintendo Switch 2 también funciona en el Nintendo Switch. No llegué a probarlo en mi Switch viejo porque me preguntó si quería importar el archivo guardado (al usar Nintendo Online, se respalda el guardado en los servidores de Nintendo), y me asusté y cerré por las dudas. No hubo edición especial como Metroid Dread, la cual hasta incluía un libro de arte. Pero sí 3 amiibos distintos, de los que no compré ninguno.

Metroid Prime 4: Beyond

Mis primeras impresiones fueron muy positivas. Me entró la emoción de estar jugando un Metroid Prime nuevo. La introducción tiene bastante acción y muy rápido todo se vuelve familiar. Los controles son súper cómodos, controlar a Samus con el Pro Controller es genial.

Al día de hoy sigo sin probar el modo mouse en el Nintendo Switch 2, pero también se puede usar si se quiere. Lo que sí probé un poco fue jugar con los Joy Con como si fueran Wiimotes. Recuerdo haber jugado hace unos años así en la casa de un amigo. Creo que fue o el original en Wii o Metroid Prime 3: Corruption. Pero recuerdo tener que mover el brazo para abrir cosas y apuntar, y en su momento me gustó mucho. Pero bueno, fue sólo un rato para alimentar la nostalgia.

Jugué todo el resto del juego con mi Nintendo Switch Pro Controller. No he tenido la necesidad de comprar un Pro Controller de Switch 2. La única funcionalidad extra que le veo es "despertar el Nintendo desde el control" y nunca usé GameChat. La televisión está a dos pasos del sillón, me parece que no amerita... (todavía). Pero como decía, Samus se controla muy bien. También podemos apuntar con los controles de movimiento en el Pro Controller, lo cual es hasta necesario en algunas partes para tener más precisión o por la naturaleza de algún jefe.

Me llamó la atención lo espectacular que se ve todo. No necesariamente porque los gráficos sean ultra realistas, pero están muy bien logrados. Jugué en el modo con mejores gráficos, no el performance que nos permite jugar a 120Hz que ni sé si mi tele lo soporta. Retro Studios creó un mundo muy llamativo y con atención al detalle. Es el juego que más capturas de pantalla he sacado por lejos en cualquier consola. A veces me demoraba en avanzar porque me ponía admirar los detalles en los ambientes. ¿Alguien más se cuelga a mirar los renders de agua en los videojuegos?

Metroid Prime 4: Beyond

La ambientación de los distintos biomas es muy particular. Hay uno en particular que se siente como muy misterioso y un poco aterrador. Era como estar en la película Alien, que justamente fue una de las influencias de Metroid. También tiene secuencias muy cinematográficas que acompañan muy bien la aventura.

La banda sonora también suma. En Fury Green, el lugar donde empieza la aventura principal, la música me dió "es muy Metroid Prime". Y se destacan también los temas de otros lugares. Los gritos de Samus suenan bastante dolorosos cuando algún enemigo nos daña. Y logra esa tensión de escuchar algo a veces que no vemos, y no sabemos si realmente está ahí. Le da esa percepción de ser un mundo viviente, con organismos acá y allá, muy bueno.

Como decía al principio, se siente como Metroid Prime en esencia, pero "nuevo". Tanto el mundo como los personajes, es exactamente lo que quería. Otro título de la saga, pero "distinto". Si bien no es perfecto, ya llego a eso, el balance es muy positivo.

Una de las ideas nuevas son los personajes que acompañan a Samus, soldados de la Federación Galáctica. La idea de los personajes en sí está bien, creo que podrían funcionar para ayudar a avanzar la jugabilidad o la historia. Incluso la conexión con la Federación Galáctica, y expandir el mundo de Samus, está bueno. Pero como otros intentos de esto último, la ejecución no fue muy buena.

El primer personaje que nos encontramos se convirtió en meme por lo mal escrito que está. Myles McKenzie es un "nerd" cuyos diálogos iniciales parecen escritos por alguien que consumió demasiadas sitcoms y películas malas de Estados Unidos hasta 1999. El el único personaje que usa lentes, porque cómo nos daríamos cuenta que es nerd sino... Y su presentación desencaja totalmente con el resto de la ambientación. La impresión que me dió fue de ser el equivalente a Jar Jar Binks.

Otro aspecto negativo que no se lo atribuyo necesariamente al personaje o cómo está escrito es el "hand-holding" (que te lleven de la mano). Cuando en un juego te ayudan al punto de hacerte enojar. Eso cae en el personaje de McKenzie durante el juego. Entiendo por qué está ahí, Metroid Prime 4 va a ser el primer Metroid de mucha gente. Esto de repente lo hace más amigable a principantes.

Imagino que Nintendo incluso pudo haber sido quien determinó que el juego necesitaba una guía que te dijera a cada rato qué hay que hacer o dónde hay que ir ahora. Lo han hecho un poco con los juegos de Mario, que pasaron de ser un ejemplo de aprender jugando con Super Mario Bros. a "te explico todo con un personaje secundario que no deja de hablar" en títulos más recientes.

Pero es un concepto que resulta medio opuesto a lo que es Metroid. Parte de la gracia de Metroid es perderse, volver para atrás, explorar. Entiendo que es una funcionalidad que puede ayudar. Pero debería ser opcional. Generalmente las ayudas no me aportaron nada, y muchas veces me decían "ahora andá a tal lugar" estando en camino a dicho lugar. Pero bueno, es un detalle, se podría mejorar.

El resto de los personajes no me molestaron tanto. Sí resulta un poco raro que tengan conversaciones con Samus quien a veces ni siquiera es capaz de responder con un gesto de las manos o moviendo la cabeza. Entonces queda como incómoda la conversación unilateral. Pero también imagino que quieren mantener la idea de que uno asume el rol de Samus al jugar Metroid el estilo Link en Zelda. Y también para alejarse de Metroid: Other M supongo.

Y ya que menciono Zelda, no pude evitar encontrar potenciales influencias de Breath of the Wild, tanto en el estilo como las ideas. En el desierto hay Shrines, que incluso visualmente me recuerdan a BotW. ¿Será que todo tiene que ser open world ahora?

Metroid Prime 4: Beyond - Vi-O-La

La moto Vi-0-La es un concepto nuevo que está muy bueno. Es fácil y divertida de manejar. Me entretuve bastante rato manejando por el desierto, recogiendo cristales verdes y haciendo la derrapada Akira constantemente. Pero creo que no se desarrolló tanto su potencial. El desierto está bastante vacío, y los enemigos que aparecen no son muy interesantes de vencer ni muy variados.

La forma en que nos la presentan es muy rara. Nos tiran en un tutorial en una pista de carreras futurista que se siente muy desconectado: "¿Por que estoy jugando F-Zero en Metroid?". A pesar de esos detalles, me gusta que la hayan agregado y ojalá desarrollen ese potencial un poco más en futuras entregas. Y sacando todo eso, es entretenido manejarla.

También podría mencionar que algunas cosas parecen como de relleno (como la búsqueda de cristales verdes). Cosas que se le agregan para que usemos una mecánica en particular (en este caso Vi-O-La) y alargar el tiempo de juego, pero que no aportan realmente.

Por último un problema que tengo que también se atribuye a títulos anteriores. El juego cuenta con los mismos sistemas de guardado, tenemos que encontrar las estaciones y guardar. También tiene checkpoints que se autoguardan, pero algunas veces guardan mucho tiempo antes de terminar la partida. Una de las veces que perdí, tuve que volver a por lo menos media hora antes. Entiendo que esto fuera así en el GameCube por limitaciones de hardware o lo que sea. Pero que en 2025 esto siga siendo un problema es un poco frustrante.

Metroid Prime 4: Beyond - Morph ball

Imagino que es posible que algunos de estos detalles sean consecuencia del desarrollo complejo que tuvo el juego. Además de haber reiniciado su desarrollo después de 2 años, demoró bastante, e imagino que en el medio se cambió de ser un título de Switch a Switch 2. Vaya uno a saber qué pasó detrás de cámaras. Me encantaría leer entrevistas con los desarrolladores, diseñadores y demás gente involucrada en su producción. Cualquier cosa que nos deje saber más del desarrollo.

Las ideas nuevas como la moto y los personajes extra de repente no están ejecutadas de la mejor manera posible. Pero a lo mejor en unos años salga Metroid Prime 5. Y toman el feedback de los jugadores para explorar un poco más esas ideas y ejecutarlas mejor.

Asumo que la mayoría de la gente que trabajó en la trilogía original ya no están en Retro Studios. Tengo entendido que Metroid Prime Remastered fue en parte para que gente nueva del equipo aprendiera a desarrollar un Metroid Prime y estuviera lista para trabajar en este título. Teóricamente ahora tendrían a la gente a punto y con suerte tengamos uno nuevo en menos de 8 años. Todo depende de cuánto venda...

Me dieron ganas de volver a jugar Metroid Dread, terminar Metroid Prime 2: Echoes en el Game Cube y ver de conseguir para jugar Metroid Prime 3 de alguna forma. La trilogía debería estar todavía en el disco duro de mi Wii U, si la memoria (o el Wii U en sí) todavía sobrevive. Pero está guardado en una caja con todos sus implementos a unos 11.000 km de donde estoy ahora.

Como resumen, Metroid Prime 4: Beyond es un excelente juego para Nintendo Switch 2. Mantiene la esencia de la saga, agrega algunos aspectos nuevos con resultados variables, pero expande el mundo de Samus. Tiene una excelente presentación, jugabilidad muy buena y entretenido para seguidores de Metroid. ¡Recomiendo!

Metroid Prime 4: Beyond - Final

El post Metroid Prime 4: Beyond - Nintendo Switch 2 fue publicado originalmente en Picando Código.

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

Variable not found

Enlaces interesantes 632

diciembre 22, 2025 07:05

Estampida arrasando una oficina con desarrolladores

Mucho contenido interesante en la última recopilación del año 🙂

Me ha alegrado verde nuevo a Juan María Hernández que, tras algunos años de parón, vuelve con una reflexión bastante certera sobre por qué el proceso de desarrollo es cada vez más lento y costoso conforme los productos van creciendo en complejidad. Os recomiendo su lectura.

También me ha parecido interesante el artículo de Alexey Fedorov sobre el devastador efecto de una estampida en la caché de nuestras aplicaciones, junto con algunas estrategias para evitarlo.

El proyecto MinimalWorker, de Joshua Jesper Krægpøth Ryder, puede resultar útil para reducir significativamente el boilerplate necesario para registrar workers en aplicaciones ASP.NET Core y .NET.

Vladan Petrovic nos muestra TUnit, un nuevo framework de testing para .NET que promete ser una alternativa interesante a los ya existentes.

Y, como siempre, vale la pena leer a Derek Comartin, esta vez reflexionando sobre por qué los debates sobre si debemos usar o no microservicios suelen perder el foco del verdadero problema que se intenta resolver: el acoplamiento.

Por último, como este será el último recopilatorio hasta la vuelta de las fiestas navideñas, aprovecho para desearos a todos unas felices fiestas y un próspero año nuevo 2026.

Por si te lo perdiste...

.NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI

Otros

Publicado en Variable not found.

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

Koalite

Sobre velocidad y coste de desarrollo

diciembre 19, 2025 09:19

Al desarrollar software, y más cuando se trata de un producto maduro, es habitual que surga la sensación de que «antes sacábamos cambios rápido y ahora todo va más lento» y, por tanto, se proponga «contratar más gente para volver a ir rápido».

Desde fuera puede parecer que el equipo simplemente se ha vuelto menos eficiente. Desde dentro, normalmente lo que está pasando es bastante más mecánico y predecible:

  • A medida que el software crece, su coste mínimo de mantenimiento y evolución sube.
  • A medida que crece el equipo, la capacidad productiva media por persona decrece.

Esto, que puede parecer algo exclusivo del mundo del desarrollo, es algo que pasa en más ámbitos, como el nivel de vida de una persona o algo tan básico como organizar una habitación.

La complejidad tiene un coste

Cuando un software es pequeño, tiene pocas piezas, pocas reglas, pocas integraciones y pocos casos especiales. Cambiar algo es parecido a mover un mueble en una habitación vacía: lo haces rápido y rara vez rompes nada.

Con el tiempo el producto crece: más funcionalidades, más pantallas, más configuraciones, más clientes con necesidades distintas, más integraciones externas, más datos históricos, más restricciones.

El sistema se convierte en un conjunto de piezas que encajan entre sí. Y ese encaje tiene un precio. Ya no estamos moviendo un mueble en una habitación vacía; estamos intentando cambiar de sitio un armario ropero en una habitación llena de muebles.

En la práctica, esto se nota en tres cosas:

  • Entender lo que hay cuesta más: antes podías leer una parte del código y ya. Ahora entender un cambio requiere saber cómo afecta a otras piezas.
  • Hacer un cambio correctamente cuesta más : hay más validaciones, más tests, más revisiones, más compatibilidad hacia atrás, más escenarios que no puedes romper.
  • Los errores se vuelven más probables y más caros: no porque la gente programe peor, sino porque hay más interacciones posibles. Además, cuando aparece un bug, cuesta más investigar su origen.

Si lo llevamos al nivel de vida de una persona, pasa algo parecido.

Si vives con tus padres, llevas una vida sencilla y no necesitas muchas cosas, tu coste fijo es bajo y puedes llegar a fin de mes sin problemas con poco dinero. A medida que tu vida se va complicado, y te compras una casa, tienes un hijo o te compras un coche, tu coste fijo va aumentando y cada vez necesitas más dinero para llegar fin de mes.

Esto es lo que pasa en software: cuando es sencillo, un cambio puede costar un par de días, pero cuando va ganando en complejidad, ese mismo cambio puede requerir un par de semanas para poder tener en cuenta todas las interacciones con el resto del sistema.

Es una consecuencia natural de tener más cosas funcionando y más cosas que no puedes romper.

Escalar el equipo ayuda, pero con rendimientos decrecientes

Cuando el coste sube la reacción típica es: «contratemos más gente». Es algo que ayuda y tiene un impacto positivo. Pero hasta cierto punto.

Hay quien piensa que si 2 personas producen 10, aumentando a 4 producirán 20. O producirán 10, pero en la mitad de tiempo. Por desgracia, no es tan sencillo, y, en general, al aumentar el número de personas, la productividad media por persona irá disminuyendo.

¿Por qué disminuye la productividad por persona al aumentar el número de personas?

Hay dos motivos principales.

La falta de contexto. Una persona nueva puede ser muy buena, pero empieza con desventaja:

  • No conoce el producto en detalle.
  • No conoce los “porqués” históricos (decisiones pasadas, limitaciones, clientes clave).
  • No conoce los riesgos escondidos (lo que no se debe tocar sin cuidado).

Al principio, esa persona necesita tiempo de formación y, además, tiempo de otras personas para ayudarle: explicaciones, revisiones, acompañamiento, correcciones. Con el tiempo se convierte en productiva, pero no es inmediato.

El coste de coordinación interno del equipo.

Cuando un equipo es pequeño pasa mucho tiempo junto, hay pocas tareas abiertas en paralelo, y todo el mundo está al tanto de todo. Al ir creciendo esto cambia: aparecen más reuniones, más tareas en paralelo que dependen unas de otras, más necesidad de alinear criterios (qué se hace, cómo, etc.).

Aunque se pueda trabajar en más frentes en paralelo, cada iniciativa individual suele avanzar más lento porque necesita más coordinación y aumenta el coste de comunicación.

Si volvemos a compararlo con el nivel de vida, es similar a lo que ocurre con los impuestos. Supongamos que cuando tenías una vida sencilla, con 12.000€ brutos al año conseguías 1.000€ netos al mes y te podías apañar. Podrías pensar que cuando la complejidad de tu vida aumenta te basta con aumenta linealmente tus ingresos, pero no es así: si duplicas tu ingresos y ganas 24.000€ brutos al año, mensualmente sólo recibes 1.600€. Los siguientes 12.000€ no han multiplicado por dos tu capacidad de asumir costes, sino sólo por 1.6.

Algo parecido ocurre al incorporar personas a un equipo. Duplicar el tamaño del equipo no multiplica su capacidad de producción por 2, sino por un factor menor.

Conclusiones

Es necesario entender que cuando aumenta la complejidad del software los cambios cuestan más, no porque el equipo sea menos competetente, sino porque, sencillamente, los cambios son más difíciles y costosos de hacer.

Contratar más gente ayuda, pero es necesario asumir un coste inicial de formación y un coste de coordinación creciente, por lo que no cabe esperar un crecimiento de la productividad lineal con respecto al número de personas.

Para recuperar la velocidad hay que tener en cuenta otros factores, como reducir la complejidad simplificando el software, eliminando casos especiales, automatizando procesos y, sobre todo, teniendo unas prioridades claras para evitar que unas tareas acaben compitiendo con otras.

Si entendemos que el software tiene un coste fijo creciente y que los equipos tienen rendimientos decrecientes al crecer, el foco de la conversación cambia. Ya no es «¿por qué somos más lentos?», sino «¿qué complejidad estamos acumulado? ¿la necesitamos? ¿cómo la vamos a gestionar?».

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

Variable not found

¿Estás usando tus expresiones regulares en .NET de forma óptima?

diciembre 19, 2025 07:47

Desarrollador viendo como el rendimiento de su aplicación desciende

La relación de muchos desarrolladores con las expresiones regulares es de amor-odio. Aunque indudablemente son una herramienta muy potente, su uso puede ser complicado y a menudo se convierten en un dolor de cabeza.

Pero hoy no vamos a hablar de su (oscura) sintaxis, ni de lo difícil que es depurarlas, ni de cómo utilizarlas en .NET, sino de distintas técnicas que pueden ayudarnos a disparar su velocidad de proceso, algo bastante importante si las utilizamos en los procesos críticos o hot paths de nuestra aplicación.

En este artículo vamos comparar el rendimiento de distintos escenarios de uso de expresiones regulares, y cómo podemos optimizar su uso en .NET.

Chequear direcciones de email usando expresiones regulares

Como punto de partida, echemos un vistazo al siguiente código, un ejemplo donde definimos la clase estática EmailValidator, con un método IsValid() que utiliza la clase RegEx para validar el email que recibe como parámetro:

Console.WriteLine(EmailValidator.IsValid("john@server.com")); // true
Console.WriteLine(EmailValidator.IsValid("john@smith@server.com")); // false

public static class EmailValidator
{
    public static bool IsValid(string email)
    {
        string emailPattern = @"^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$";
        var regex = new Regex(emailPattern, RegexOptions.IgnoreCase);
        return regex.IsMatch(email);
    }
}

No vamos a entrar en el debate de si la expresión regular que hemos utilizado es la mejor para validar un email. Simplemente es la recomendación de un LLM asegurando que cumple la RFC 5322, y, para la prueba que queremos hacer es totalmente válida porque tiene una cierta complejidad.

Si ejecutamos el código anterior, veremos que la expresión regular funciona correctamente y el método IsMatch() nos devuelve true o false dependiendo de si el email es válido o no. Y además, aparentemente la ejecución es bastante rápida, suficiente si no es algo que se vaya a ejecutar con mucha frecuencia.

Sin embargo, internamente, cada vez que llamamos a ese método estático IsValid(), estamos instanciando la clase Regex suministrándole el patrón de la expresión regular, que es parseado, verificado, optimizado, compilado y posteriormente ejecutado por un intérprete para realizar la validación que le estamos solicitando. Todo este proceso puede ser costoso en términos de rendimiento, sobre todo si esa parte del código se ejecuta con mucha frecuencia.

Seguro que podemos mejorar esto...

Primera mejora: reutilización de Regex

La primera optimización que podemos aplicar en este punto es reutilizar la instancia de Regex. De esta forma, evitaremos la sobrecarga de crear una nueva instancia cada vez que llamamos al método IsValid() y evitaremos el proceso de verificación y compilación de la expresión regular.

Esto podríamos conseguirlo fácilmente insertando en la clase anterior el siguiente código:

public static class EmailValidator
{
    private const string EmailPattern = @"^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$";
    private static Regex SharedInstance = new Regex(EmailPattern, RegexOptions.IgnoreCase);

    public static bool IsValid_Shared(string email)
    {
        return SharedInstance.IsMatch(email);
    }
}

Si ejecutamos de nuevo la aplicación, veremos que el funcionamiento es exactamente el mismo, y que aparentemente sigue siendo igual de rápido. Pero si usamos BenchmarkDotNet para medir el rendimiento de las dos implementaciones, nos llevaremos una sorpresa:

| Method          | Mean       | Error     | StdDev    | Gen0    | Allocated |
|-----------------|-----------:|----------:|----------:|--------:|----------:|
| IsValid         | 206.716 us | 1.5089 us | 1.2600 us | 27.3438 |  233969 B |
| IsValid_Shared  |   2.742 us | 0.0312 us | 0.0276 us |       - |         - |

Esta segunda implementación se ejecuta casi 80 veces más rápido que la primera, sin consumo de memoria adicional. Impresionante, ¿verdad? Realmente se trata de una mejora brutal a cambio de muy poco esfuerzo de implementación.

Hay que tener en cuenta que las cifras no son siempre tan espectaculares, y que el rendimiento de la primera implementación puede variar dependiendo de la complejidad del patrón de la expresión regular. En expresiones más simples, la diferencia de rendimiento puede ser mucho menor, pero en cualquier caso habrá mejoras.

Pero... ¿aún podemos hacerlo mejor?

Segunda mejora: compilación de la expresión regular

Por defecto, las expresiones regulares se compilan a una serie de instrucciones de alto nivel que indican las operaciones que deben realizarse para comprobar si la cadena de texto suministrada coincide con el patrón de la expresión regular. Luego, en cada llamada a IsMatch() o métodos similares, un intérprete ejecuta esas instrucciones para realizar la validación.

Sin embargo, la clase Regex también permite compilar la expresión regular a código IL, por lo que el runtime de .NET puede ejecutarlo directamente e incluso, gracias al JIT, generar y ejecutar el código máquina nativo para la plataforma donde corre la aplicación, a cambio, eso sí, de consumir un poco más de memoria y tiempo durante su inicialización.

Esto lo conseguimos de nuevo con muy poco esfuerzo, simplemente añadiendo el RegexOptions.Compiled a la llamada al constructor de la clase Regex:

private static Regex SharedCompiledInstance 
  = new Regex(EmailPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);

Si volvemos a llevarnos las tres opciones a BenchmarkDotNet, y medimos su rendimiento, veremos que en este último caso hemos mejorado algo más el rendimiento:

| Method            | Mean       | Error     | StdDev    | Gen0    | Allocated |
|------------------ |-----------:|----------:|----------:|--------:|----------:|
| IsValid           | 202.007 us | 2.4068 us | 2.2513 us | 27.3438 |  233969 B |
| IsValid_Shared    |   2.606 us | 0.0276 us | 0.0258 us |       - |         - |
| IsValid_Compiled  |   2.570 us | 0.0141 us | 0.0132 us |       - |         - |

En este caso la diferencia es mínima, pero es algo que también depende de la complejidad de las operaciones que hay que realizar para validar los valores contra la expresión regular. Por ejemplo, si en lugar de usar la expresión regular que hemos visto anteriormente para detectar emails, ejecutamos el mismo benchmark para un patrón aparentemente simple como "(\d+)*\1" y hacemos que se compruebe un string numérico muy largo (unos 100.000 dígitos), la diferencia de rendimiento es mucho más notable:

| Method           | Mean     | Error    | StdDev   | Allocated |
|----------------- |---------:|---------:|---------:|----------:|
| IsValid          | 65.70 ms | 1.107 ms | 1.088 ms |    5401 B |
| IsValid_Shared   | 63.74 ms | 0.925 ms | 0.772 ms |      57 B |
| IsValid_compiled | 19.52 ms | 0.147 ms | 0.130 ms |      12 B |

La expresión regular "(\d+)*\1" permite buscar cadenas que contengan un número seguido de un número repetido, como por ejemplo 123123, 456456, 789789, etc. Esta expresión regular es ejemplo conocido por dar lugar al llamado catastrophic backtracking, un problema que puede dar lugar a un rendimiento muy bajo en ciertas expresiones regulares, que incluso puede ser explotado en ataques de denegación de servicio (DoS) en aplicaciones web.

Estos resultados son fácilmente explicables: la diferencia de rendimiento entre la primera y segunda opción es pequeña, porque la expresión regular es muy simple y, por tanto, el coste de su compilación es bajo. Pero el rendimiento se multiplica por tres en la tercera opción porque la ejecución de la expresión regular se beneficia de la compilación a código IL.

Hasta aquí, hemos comprobado cómo realizando un par de modificaciones simples en el código podemos lograr mejorar considerablemente el rendimiento de las expresiones regulares en .NET. Pero aún hay más...

Tercera mejora: compilar la expresión regular en tiempo de diseño

La compilación de la expresión regular a código IL es una mejora muy interesante, pero tiene un coste adicional el términos de memoria y proceso, que se produce en el momento de la inicialización de la expresión regular, es decir, en tiempo de ejecución.

De hecho, también podemos realizar un benchmark del tiempo de creación de la instancia de Regex con y sin compilación, y veremos que la diferencia es prácticamente del triple, tanto en tiempo de proceso como en consumo de memoria:

| Method              | Mean     | Error    | StdDev   | Gen0    | Gen1   | Allocated |
|-------------------- |---------:|---------:|---------:|--------:|-------:|----------:|
| CreateRegex         | 28.64 us | 0.204 us | 0.170 us |  3.4180 |      - |  29.27 KB |
| CreateRegexCompiled | 99.51 us | 0.973 us | 0.863 us | 10.7422 | 1.4648 |     90 KB |

Si queremos evitar este sobrecoste, a partir de .NET 7 podemos compilar la expresión regular en tiempo de diseño usando source generators. De esta forma, el compilador de C# generará el código C# necesario para ejecutar la expresión regular, y lo incluirá en el ensamblado de la aplicación, por lo que no pagaremos ningún coste adicional en tiempo de ejecución. Pero además, como veremos algo más adelante, el código generado será mucho más eficiente que la versión compilada en tiempo de ejecución 🙂

Para conseguirlo, en una clase cualquiera debemos un método parcial de tipo Regex y asignarle el atributo [GeneratedRegex] especificando el patrón de la expresión regular y las opciones que queramos utilizar. Por ejemplo, en el siguiente código podemos ver el método al que hemos llamado GeneratedEmailRegex() sobre la clase estática parcial EmailRegex (ambos nombres son arbitrarios):

public static partial class EmailRegex
{
    [GeneratedRegex(@"^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$", RegexOptions.IgnoreCase)]
    public static partial Regex GeneratedEmailRegex();
}

Podéis ver fácilmente el código generado ejecutando la aplicación y, en el explorador de soluciones de Visual Studio, desplegando la carpeta "External Sources", el ensamblado de la aplicación, y abriendo el archivo RegexGenerator.g.cs, o bien, siguiendo estos pasos.

Una vez tenemos este método disponible, para utilizar la expresión regular simplemente debemos usar la instancia de Regex retornada por el mismo, por ejemplo así:

public static class EmailValidator
{
    public static bool IsValid(string email)
    {
        return EmailRegex.GeneratedEmailRegex().IsMatch(email);
    }
}

Y si de nuevo nos llevamos estos cambios a BenchmarkDotNet, y medimos el rendimiento de las distintas implementaciones, de nuevo nos llevaremos una alegría:

| Method                    | Mean         | Error       | StdDev      | Gen0    | Allocated |
|-------------------------- |-------------:|------------:|------------:|--------:|----------:|
| IsValid_Initial           | 213,564.0 ns | 1,532.91 ns | 1,280.05 ns | 27.3438 |  233969 B |
| IsValid_Shared_Instance   |   2,667.7 ns |    39.86 ns |    35.33 ns |       - |         - |
| IsValid_Compiled_Instance |   2,745.5 ns |    37.81 ns |    35.37 ns |       - |         - |
| IsValid_UsingGenerators   |     788.3 ns |     7.91 ns |     7.40 ns |       - |         - |

¡Uau! De nuevo hemos conseguido dividir por tres el tiempo de ejecución de la expresión regular respecto a la versión compilada en tiempo de ejecución. Y bueno, si lo comparamos con la versión inicial, la que implementamos sin pensar en ninguna optimización, es cerca de 300 veces más eficiente.

Conclusiones

A veces, el código que escribimos puede no ser el más óptimo: a veces por costumbre, a veces por comodidad, u otras simplemente porque no conocemos fórmulas mejores. En algunos casos no importará demasiado porque quizás nuestros requisitos de rendimiento no son excesivamente exigentes, pero en otros muchos escenarios sí debemos prestar atención a este tipo de detalles.

Lo que hemos visto en este post es un claro ejemplo de cómo las mejoras que se van introduciendo en el framework y el SDK de .NET pueden ayudarnos a mejorar el rendimiento de nuestras aplicaciones con muy poco esfuerzo.

Publicado en: www.variablenotfound.com.

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

Variable not found

Enlaces interesantes 631

diciembre 15, 2025 07:42

Puesto de trabajo de desarrollador inquieto por la IA

La semana pasada estuve unos días fuera y no publiqué la habitual recopilación de los lunes. Pero ya me he puesto al día, y, como se me acumuló el trabajo, en esta entrega tenemos más de ¡100! enlaces a contenidos a los que vale la pena echar un vistazo.

Por destacar algunos, en primer lugar el profundo análisis que está llevando a cabo Martin Stühmer sobre soluciones de scheduling en .NET, muy interesantes para estar al tanto de las opciones disponibles.

También Gerson Azabache ha publicado varios artículos interesantes sobre ASP.NET Core, como la comparativa entre Minimal APIs y controladores, resultados tipados y algunas buenas prácticas en el desarrollo de APIs empresariales.

Braulio Díez comparte sus reflexiones y experiencias sobre el impacto de la IA en la programación y el futuro de los desarrolladores de software, que igual no es tan malo como algunos pintan.

Y en la misma línea, José Manuel Alarcón habla sobre cómo los juniors deben enfocar su proceso de aprendizaje, integrando la IA como una aliada imprescindible.

Muchos más enlaces, a continuación.

Por si te lo perdiste...

.NET

<!--more-->

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI / Cross-Platform

Otros

Publicado en Variable not found.

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

Picando Código

Anunciado Mega Man: Dual Override

diciembre 12, 2025 11:30

Capcom anunció la duodécima entrega principal de la serie Mega Man durante The Game Awards: Mega Man: Dual Override. El bombardero azul regresa en 2027 en Nintendo Switch 2, Nintendo Switch, PlayStation 5, PlayStation 4, Xbox Series X|S, Xbox One y PC a través de Steam.

Mega Man Dual Overrida

El último título en la serie fue Mega Man 11 en 2018. Parece que Capcom nos va a dar un Mega Man nuevo por década aproximadamente 😅 En 2027 se celebran 40 años de Mega Man, así que es posible que hayan más anuncios al respecto durante el año.

En el mundo de los cómics, después de una muy buena serie Mega Man Timelines durante 2025, vamos a tener cómics de Mega Man X. El primer número, Mega Man X #0, va a estar disponible en Enero de 2026, seguido de una mini-serie de 5 números. Esperemos ver algo de Mega Man X en el terreno de los videojuegos también...

El tráiler del anuncio muestra que sigue el estilo gráfico 2.5D de Mega Man 11. De repente se notan algunos detalles más en lo gráfico. Vuelve la clásica deslizada y el disparo cargado con el mega buster. Hacia el final del tráiler vemos una animación como de expansión de elementos en la armadura de Mega Man. ¿Cómo estará relacionado eso al juego? Habrá que ver también qué protagonismo tiene Proto Man, del que escuchamos el silbido característico al final del tráiler. Por el momento no hay mucho más información, pero seguro sepamos más el año que viene.

Mega Man: Dual Override

Jugué Mega Man 11 en su momento en Nintendo Switch y lo disfruté mucho. Hace poco lo empecé de nuevo, a ver si lo vuelvo a terminar. Es entretenido y desafiante, como nos tiene acostumbrados la saga. En ese título se introdujo una mecánica nueva, el sistema "Double Gear". Este incluye dos habilidades, Speed Gear que permite enlentecer el tiempo, permitiendo atacar y esquivar ataques más fácilmente. La otra es Power Gear, que permite disparar ataques más potentes. Ni idea si esto vuelve en Mega Man 12.

Si todavía no han probado Mega Man 11, en los próximos días va a recibir un descuento en tiendas digitales. Va a estar de oferta en la PlayStation Store, Nintendo eShop, Xbox Store y Steam. También hoy recibió una actualización que expande las opciones de idioma a portugués brasileño y español latinoamericano.

Siguiendo con Mega Man: Dual Override, este mes Capcom organiza un concurso especial de diseño de jefes. Como hizo en alguna entrega anterior hace muchos años, tendremos la oportunidad de crear un nuevo robot que aparecerá en el juego:

Periodo de inscripción: 11 de diciembre de 2025, 22:00 h - 1 de enero de 2026, 01:59 h CST
Convocatoria: Estamos aceptando inscripciones en X (antes Twitter) para el concurso de diseño de Robot Maestro para Mega Man: Dual Override. ¡Utiliza el modelo de abajo como base para crear tu propio diseño único de un Robot maestro con un brazo de succión gigante!
Aceptaremos diseños de las siguientes cuatro regiones: Japón, las Américas, Europa y Asia.
Buscamos diseños de un Robot maestro que tenga un brazo derecho con inmensos poderes de succión!
Premios: Elegiremos los 6 mejores diseños y seleccionaremos un ganador entre ellos.
- Gran premio: 1 ganador
Tu diseño de Robot maestro se usará en Mega Man: Dual Override
- Premios a la excelencia: 6 ganadores
Tu nombre aparecerá en los créditos de Mega Man: Dual Override

Voy a ver si mando algo... Una lástima que el concurso se haga a través de ese sitio web al que las marcas ya deberían haber abandonado hace rato.

Todavía falta al menos un año entero para poder jugar Mega Man Dual Override. Pero es bueno ver que Capcom no se ha olvidado de Mega Man.

Otro título interesante de Capcom que recibió noticias durante el evento fue Pragmata. Cuando vi el primer tráiler me resultó un juego "como un Mega Man más adulto". Es una IP nueva de Capcom, aventura de acción y ciencia ficción con elementos de hackeo. ¡Se ve muy bien! Mediante un tráiler nuevo, se anunció su disponibilidad también para Nintendo Switch 2. Además está disponible una demo gratuita en Steam, y próximamente va a haber demo para Nintendo Switch 2, PlayStation 5 y Xbox Series X|S. El juego va a estar disponible el 24 de abril de 2026 en todas las plataformas, algo para ir jugando mientras esperamos Mega Man 12...

YouTube Video

El post Anunciado Mega Man: Dual Override fue publicado originalmente en Picando Código.

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

Picando Código

Piques Firefox: Contar cantidad de pestañas abiertas en Firefox 2025

diciembre 11, 2025 11:30

Hace unos años publiqué el pique para contar las pestañas abiertas en Firefox. Me sirve para convencerme de que tengo demasiadas pestañas abiertas y que los 16GB de Ram de mi laptop no son suficientes para aguantar tanta cosa. Pero desde hace un tiempo esto no me venía funcionando. Al abrir la consola del navegador con Ctrl Shift J, no me aparecía la línea de comando. Así que no podía ejecutar comandos.

Resulta que desde hace algunas versiones de Firefox la línea de comando de la consola del navegador está deshabilitada por defecto. Para habilitarla, tenemos que ir a about:config en la barra de dirección de Firefox y cambiar el valor de devtools.chrome.enabled de false a true. Tambien se puede habilitar seteando la opción "Enable browser chrome and add-on debugging toolboxes" en las preferencias de las Web Developer Tools.

Así que pude volver a contar mis pestañas abiertas en Firefox:

>> gBrowser.tabs.length
← 445

Debería seguir cerrando algunas 🙈

De esa misma página de documentación de Firefox que enlacé: La consola del navegador es como la consola web, pero aplicado a todo el navegador en vez de al contenido de una pestaña única. Loguea un montón de información como pedidos de red, JavaScript, CSS, seguridad, errores advertencias y más pero de todo el contenido abierto. Podemos ejecutar JavaScript, y tenemos acceso a todas las pestañas a través de la variable global gBrowser. También podemos modificar la interfaz del navegador al tener acceso al objeto window, cerrar pestañas con código y mucho más.

Tendría que buscar algo divertido para programar con este conocimiento. Pero por ahora me limito a contar las pestañas abiertas a mano cada vez que pienso que tengo demasiadas. Hay un montón de extensiones de Firefox diseñadas con este mismo propósito, pero para qué instalar una extensión más si se puede hacer en pocos pasos.

El post Piques Firefox: Contar cantidad de pestañas abiertas en Firefox 2025 fue publicado originalmente en Picando Código.

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

Picando Código

[Libro] Mike Drucker - Good Game No Rematch

diciembre 04, 2025 11:15

Mike Drucker - Good Game No Rematch

Mike Drucker es un escritor y comediante. Escribió para programas de televisión como Bill Nye Saves the World, The Tonight Show y Full Frontal with Samantha Bee. Ha contribuido a The Onion y Saturday Night Live (el actor de Scrubs hizo de él en un sketch de SNL). Pero más importante (para mí) que todo eso, trabajó en Nintendo y escribió la localización al inglés de Kid Icarus Uprising, entre otras cosas. Ah, ¡también escribió un cómic de Spider-Man!

Solía seguirlo en Twitter, y como muchos hicimos, abandonó el barco cuando se destapó como antro fascista. Pero se abrió un newsletter al que me suscribí desde el primer día: At The Mountains of Sadness, está alojado en Substack. Substack es otro sitio web que se destapó como antro fascista, y Mike Drucker está al tanto y tiene planeado migrar a Ghost. Pero estas migraciones son más complicadas de lo que parecen y requieren un montón de tiempo y esfuerzo...

Hace un buen tiempo ya, anunció en su newsletter que había vendido la idea del libro. No sé cómo funciona eso, supongo que uno presenta parte de lo que tiene escrito a una empresa que se compromete a pagar para publicarlo. En fin, el tema es que desde entonces lo esperé con ansias. Habiendo disfrutado mucho de lo que escribía tanto en su newsletter como en artículos que enlazaba, tenía muchas ganas de leerlo.

Lo describía como una colección de ensayos sobre videojuegos. Y si bien es cierto en parte, los capítulos tienen una cohesión cronológica que van contando experiencias en distintas etapas. El elemento que conecta todo son los videojuegos, con referencias y chistes, pero han sido algo muy presente en su vida. El libro está dividido en cuatro secciones principales que agrupan capítulos de las distintas etapas de las que escribe. Algunos capítulos son más cortos con contenido más al estilo lista como Manuales de videojuegos a través de las décadas. Éstos son como experimentos literarios que me recuerdan al trabajo de mi amigo Nacho Alcuri, por ejemplo:

What your favorite classic arcade game says about you (Lo que tu juego clásico de maquinitas favorito dice de tí)

  • Street Fighter 2: You're already a little mad I didn't specify which Street Fighter 2.
    Street Fighter 2: Ya estás un poco enojado que no especifiqué cuál Street Fighter 2.

Si bien es un libro gracioso, también tiene historias muy personales e identificables. No recuerdo la última vez que un libro me hizo lagrimear como éste, encima más de una vez. No sólo son historias emocionantes (y devastadoras), algunas experiencias resultan dolorosamente identificables: I'm a man who plays fighting games alone without considering the depths of sadness that represents (soy un hombre que juega juegos de pelea sólo sin considerar las profundidades de tristeza que eso representa... ¡OUCH! No sé si necesitaba que un libro me dijera lo triste que soy).

Su humor es autocrítico al extremo. Mientras leía pensaba "qué forma de darse palo, pero sabemos que es hipérbole, al final del día es una persona que dentro de todo hace las cosas bien y tiene relativo éxito. Pero tanto autocrítica al final le puede jugar en contra porque... ¿Dónde escuché esto antes?" Y ahí me pegó como si me hubiera chocado contra un muro y recordé las tantas veces que escuché ese discurso dirigido a mi persona, particularmente en el ámbito profesional. También es que me gusta mucho el humor autocrítico y cínico. Otro ejemplo de su newsletter: from 1977, long before my parents cursed me with life (de 1977, mucho antes que mis padres me maldijeran con la vida).

Con eso y otras tantas experiencias generé esa conexión con el libro que está escrito por Mike Drucker pero al momento de liberarlo al mundo se vuelve la experiencia única de cada individuo que lo lee y el artista pierde el control. Uno trae a un libro todo de sí mismo y saca de él enriquecimiento diverso. Como comenté antes, me generó diversas emociones, más que nada risa e identificación. También disfruté mucho de las anécdotas relacionadas a los videojuegos, ese conocimiento anecdótico de la historia de esto que tanto me apasiona es mi adicción.

Tras leerlo me fui a fijar algo que sospechaba y sí, Mike Drucker y yo somos de la misma generación. Nació un año antes que yo. Salvando las diferencias geográficas y sociales, hay mucho en común. Es un libro gracioso y entretenido, pero si nacieron en las décadas de 1980 o 1990 y crecieron jugando videojuegos, probablemente encuentren mucho en común también.

¿Quiero jugar Nier: Automata después de leer este libro? Sí. ¿Va a empeorar mi depresión? Probablemente. ¿Este párrafo está inspirado en el estilo del libro? Gracias por usar "inspirado en el" y no "robando del", voz imaginaria en mi cabeza que se hace preguntas retóricas a mí mismo.

Es un libro que me gustó mucho, recomiendo y me hizo reír, llorar, y querer estar en una cadena de texto con Mike Drucker por alguna razón. Es un muy buen regalo para gente aficionada a los videojuegos, se ve muy lindo en la biblioteca y seguramente vuelva a leer. El autor es un tipo famoso por las cosas que ha escrito (programas importantes de televisión y más), pero a mí me llega porque es terrible nerd. Y si ves el término nerd como algo distinto al mayor de los cumplidos, estás leyendo el blog equivocado.

El post [Libro] Mike Drucker - Good Game No Rematch fue publicado originalmente en Picando Código.

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

Variable not found

Soporte para el TLD .localhost en ASP.NET Core 10

diciembre 02, 2025 07:05

Desarrollador trabajando en una aplicación web

Al desarrollar aplicaciones ASP.NET Core (APIs, MVC, Razor Pages o Blazor) y ejecutarlas en local, ya sabes que todas ellas comparten el mismo nombre de host: localhost, y lo único que las diferencia es el puerto en el que se encuentran a la escucha.

Esto puede dar lugar a ciertos problemas. Aparte de no ser sencillo identificarlas a partir de la URL mostrada en el navegador, hay ciertos recursos web que pueden mezclarse entre proyectos (por ejemplo, las cookies) y pueden dar lugar a comportamientos inesperados.

En ASP.NET Core 10 se ha puesto solución a esto añadiendo el soporte para el TLD (Top Level Domain) .localhost, lo que permite que cada aplicación pueda tener su propio nombre de host único.

Lo vemos a continuación.

Soporte para TLD .localhost en ASP.NET Core 10

El nombre .localhost es un dominio de nivel superior (TLD, Top Level Domain) reservado por las RFC 2606 y 6761 para ser utilizado en entornos de desarrollo y pruebas, y siempre está asociado a la dirección de loopback, es decir, a la dirección local del propio equipo.

Por tanto, cualquier nombre de host que termine en .localhost (por ejemplo, miapp.localhost, api.localhost, MyApp.dev.localhost, etc.) debería resolverse siempre a la dirección IP 127.0.0.1 o ::1, dependiendo de si se utiliza IPv4 o IPv6.

A partir de ASP.NET Core 10, Kestrel entenderá que todos los nombres de host que terminen en .localhost son alias válidos para localhost, por lo que podemos utilizarlos para configurar el servidor, definir las URLs de nuestras aplicaciones (tanto en launchSettings.json como en variables de entorno), etc. Esto nos permitirá usar distintos nombres de host para cada aplicación, evitando los problemas mencionados anteriormente.

Otro tema que han actualizado es el certificado HTTPS utilizado en desarrollo. Dado que el antiguo certificado solo era válido para localhost, al utilizar otros nombres de host el navegador mostraría advertencias de seguridad. Por esta razón, el certificado que se registra al instalar .NET 10 es un wildcard del dominio *.dev.localhost.

Observad que no han podido hacerlo directamente para soportar *.localhost. Han tenido que introducir el subdominio .dev por delante porque no es posible crear wildcards sobre top level domains como localhost.

En la práctica, esto implica que podremos asignar a nuestras aplicaciones ASP.NET Core nombres de host como miapp.dev.localhost, api.dev.localhost, etc., aunque no es algo que esté habilitado por defecto.

Para activar esta característica, debemos seleccionar la opción "Use the .dev.localhost TLD in the application URL" al crear una nueva aplicación, como se muestra en la siguiente imagen:

Pantalla de creación de una aplicación ASP.NET Core, seleccionando el uso del TLD .dev.localhost

Al hacerlo, se configurará el launchsettings.json para que utilice el nombre de proyecto como subdominio. Por ejemplo, a continuación se muestra la configuración generada para el proyecto MyWebApplication, donde podemos ver el uso del host mywebapplication.dev.localhost:

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://mywebapplication.dev.localhost:5244",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://mywebapplication.dev.localhost:7279;
                         http://mywebapplication.dev.localhost:5244",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

También podemos conseguir lo mismo si utilizamos la línea de comandos de .NET para crear los proyectos. Por ejemplo, el siguiente comando crea una aplicación MVC que utiliza el TLD .dev.localhost:

C:\MyProjects\MyWebApp>dotnet new web --localhost-tld
The template "ASP.NET Core Empty" was created successfully.

Processing post-creation actions...
Restoring C:\MyProjects\MyWebApp\MyWebApp.csproj:
Restore succeeded.


C:\MyProjects\MyWebApp>type .\Properties\launchSettings.json
{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://mywebapp.dev.localhost:5024",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://mywebapp.dev.localhost:7125;
                         http://mywebapp.dev.localhost:5024",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}
C:\MyProjects\MyWebApp>_

Con estas configuraciones, al lanzar el proyecto se utilizarán estos nombres de host exclusivos para el proyecto, evitando los problemas de compartir el mismo localhost entre varias aplicaciones.

C:\MyProjects\MyWebApp> dotnet run
Using launch settings from C:\MyProjects\MyWebApp\Properties\launchSettings.json...
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://mywebapp.dev.localhost:5024
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5024
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\MyProjects\MyWebApp
_

Un último detalle importante: podremos utilizar los nombres de host personalizados cuando accedamos a las aplicaciones desde el navegador web, pero probablemente no desde otras herramientas como curl, Postman, etc., o al menos de directamente.

Esto se debe a que, aunque el TLD .localhost está reservado para este propósito, no todas las aplicaciones cliente o los sistemas operativos resuelven automáticamente estos nombres a la dirección de loopback. Por esta razón, en estos casos tendríamos que añadir entradas manuales en el archivo hosts de nuestro sistema operativo para que los nombres personalizados funcionen correctamente.

Afortunadamente, los navegadores web modernos implementan esta resolución de forma automática, por lo que funcionará directamente 🙂

Publicado en Variable not found.

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

Una sinfonía en C#

¿Cómo conectar Kakfa-UI con Event Hubs de Azure?

diciembre 02, 2025 12:00

“Introducción”

Si usamos Eventhubs de Azure como broker Kafka, y queremos usar Kafka-UI para monitorizar los topics, tenemos que tener en cuenta algunas cosas para que funcione. Hablando siempre de autenticación utilizando SASL_SSL con mecanismo PLAIN. (Esto no funciona para Managed Identity).

En principio sabemos que podemos definir un connection string SAS para conectarnos a Event Hubs, pero Kafka-UI no soporta directamente este formato, por lo que tenemos que hacer algunos ajustes.

KAfka en generar no soporta este formado, sino que hay que hacer un mapeo de los valores del connection string a las propiedades que Kafka espera, más específicamente en el usuario y password, además de protocolo de comunicación.

Configuración de Client Kafka

Para conectar un cliente Kafka a Event Hubs, tenemos que mapear los valores del connection string a las propiedades de usuario y password. Pero primero hay que configurar:

  • Protocol: SASL_SSL
  • Mechanism: PLAIN

Y luego en las propiedades de autenticación:

  • Username: $ConnectionString
  • Password: Endpoint=sb://.servicebus.windows.net/;SharedAccessKeyName=;SharedAccessKey=;EntityPath=

El EntityPath es opcional, y solo si queremos conectarnos a un Event Hub específico. Si no se especifica, se puede acceder a todos los Event Hubs dentro del namespace.

Básicamente el username es el literal $ConnectionString (con el signo $) y el password es el connection string completo.

Conectar Kafka-UI

En el caso de Kafka-UI tenemos un truco adicional, que sería agregar al user name un $ adicional al inicio, quedando así:

  • Username: $$ConnectionString
  • Password: Endpoint=sb://.servicebus.windows.net/;SharedAccess

Esto en la propiedad KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG (reemplazar el 0 por el índice del cluster que estemos configurando).

En el caso de un docker-compose.yml, quedaría algo así:

version: '2'
services:
  kafka-ui:
    image: provectuslabs/kafka-ui:latest
    ports:
      - 9999:8080
    environment:
      - KAFKA_CLUSTERS_0_NAME=azure
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=xxxx.servicebus.windows.net:9093
      - KAFKA_CLUSTERS_0_PROPERTIES_SECURITY_PROTOCOL=SASL_SSL
      - KAFKA_CLUSTERS_0_PROPERTIES_SASL_MECHANISM=PLAIN
      - KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG=org.apache.kafka.common.security.plain.PlainLoginModule required username='$$ConnectionString' password='Endpoint=sb://<NAMESPACE>.servicebus.windows.net/;SharedAccessKeyName=<KEY_NAME>;SharedAccessKey=<KEY_VALUE>';

El connection string tiene que tener scope del namespace (lo que sería el broker de Kafka).

Especial cuidado al doble $ en el username y al ; final

Nos leemos.

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

Variable not found

Enlaces interesantes 630

diciembre 01, 2025 07:01

Un usuario caminando feliz por el happy path

Esta semana me gustaría destacar en primer lugar el detallado análisis de Andrew Lock sobre el proceso de arranque de una aplicación .NET, muy interesante para saber cómo funcionan las cosas por dentro.

Bipin Joshi da un gran repaso a Kestrel, el motor de todas las aplicaciones ASP.NET Core: cómo configurarlo, tunearlo, ejecutarlo y buenas prácticas de uso.

Milan Jovanović nos recuerda que el happy path no es el único camino en nuestras aplicaciones, y nos muestra técnicas para desacoplar servicios para hacerlos más robustos.

Por último, Ricardo Peres nos habla de la relación entre tipos anulables y miembros requeridos en C#, algo que, cuando empezamos a trabajar con ellos, puede resultar algo confuso.

El resto de enlaces, a continuación.

Por si te lo perdiste...

.NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI

Otros

Publicado en Variable not found.

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

Variable not found

Enlaces interesantes 629

noviembre 24, 2025 07:05

Programador usando un ordenador Minivac en los años 60

Años atrás, en los inicios de la informática, se programaba de forma bastante diferente: conectando cables y usando paneles de interruptores. Por eso me ha parecido muy curioso el simulador del Minivac 601, un ordenador de los años 60,  donde podemos probar de primera mano cómo era su experiencia de uso.

Y continuando con temas vintage, Microsoft ha anunciado la liberación del código fuente de los juegos Zork I, II y III, la mítica saga de aventuras conversacionales de los años 80. Pura historia del software.

También esta semana encontramos una interesante lectura de Sudhir Mangla donde explica cómo usar patrones modernos y características recientes de C# para construir modelos más expresivos, seguros y mantenibles que los que ofrece la aplicación estricta de SOLID.

El resto de enlaces interesantes recopilados esta semana, entre los que podéis encontrar información sobre .NET 10, ASP.NET Core, IA, desarrollo web y mucho más, los tenéis a continuación.

Por si te lo perdiste...

.NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI

Otros

Publicado en Variable not found.

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

Arragonán

Viviendo en el péndulo. Hasta la vista Genially

octubre 13, 2025 12:00

Tras casi 4 años, esta fue mi última semana en Genially. Una decisión que me costó mucho tomar tanto por motivos personales, con un ambiente de compañerismo en la compañía que creo que no es habitual en otros lugares que tienen cierta escala y haber construido lazos con un buen puñado de personas; como por motivos profesionales, con unos cuantos desafíos que se venían a corto y medio plazo en los que sé que hubiera disfrutado y aprendido.

En este tiempo, mi rol en la empresa se fue transformando poco a poco casi sin darnos cuenta, primero influenciando solo a nivel de tecnología y terminando haciéndolo a nivel de producto, negocio y operaciones. Hubo algo que fue una constante: vivir en el péndulo entre individual/team contributor y el management.

Incorporación

Entré casi por casualidad. Conocí a Chema, CTO de Genially, unos años antes en una Pamplona Crafters y mantuvimos el contacto vía redes sociales (cuando tuiter aún molaba). Tiempo después, hablamos por otro tema y me propuso explorar si tenía sentido incorporarme. La compañía venía de crecer mucho y vieron que podía asumir un rol que resultase complementario.

Justo era un momento en el que empezaba a sentir que necesitaba un cambio profesional, pero quería estar seguro de mi siguiente paso. Así que tras haber hecho el proceso de selección, nos tomamos un par de meses y tuvimos varias conversaciones hasta que finalmente me incorporé a la compañía.

Plataforma y organización

Entré con un rol de Platform Lead, por lo que mi responsabilidad iba a ser ayudar a los equipos de producto a que pudieran enfocarse en tener impacto, tratando de mejorar la experiencia de desarrollo y la efectividad de los equipos. Como bonus, también iba a echar una mano en cuestiones más organizativas.

Aunque este era un rol de liderazgo, no había un equipo dedicado, de modo que iba a tener que influir, colaborar con distintos equipos y empujar algunas iniciativas por mi cuenta.

Sobre el trabajo de plataforma

Una vez hecho el onboarding, empezar a tener algunas iniciativas ya lanzadas y conociendo más la compañía, traté de aterrizar una serie de metas:

Las iniciativas y actividades de plataforma deben facilitar la Developer Experience y ayudar a los equipos en distintos aspectos:

  • Reducir su carga cognitiva, que se enfoquen en complejidad intrínseca y no en la extrínseca, potenciando la germana (generando aprendizaje, construyendo esquemas o automatizando su uso)
  • Habilitar actitudes data-informed en la toma de decisiones
  • Aportar la mayor autonomía y empoderamiento posibles
  • Tratar de ser lo más eficientes en cuestiones de costes económicos
  • Dar fiabilidad, que las herramientas apenas fallen

Metas que traté de tener en cuenta, definiendo e implantando prácticas, procesos y herramientas, automatizando tareas, creando documentación… Y darles seguimiento unas veces de manera cuantitativa y otras de forma cualitativa.

Algunas de las iniciativas más relevantes fueron estas:

  • Actuar como puente entre el equipo de infraestructura y los equipos de producto para acelerar la implantación del stack de observabilidad de Grafana (Loki, Mimir, Tempo).
  • Formalizar la redacción de postmortems blameless tras incidencias que afecten al servicio junto a CTO y VP de ingeniería, para fomentar el aprendizaje sistémico.
  • Apoyar al equipo de Design System con distintas actividades.
  • Ayudar en la introducción de Snowplow + Amplitude para la instrumentación de producto colaborando con el equipo de data y los primeros equipos de producto involucrados.
  • Introducir el uso de Turborepo en el monorepo para simplificar el proceso de build.

A nivel organizativo

Durante esos primeros meses se estaba planteando una reorganización del área de desarrollo de producto bastante importante. Básicamente era pasar de una estructura de squads que se organizaba de forma recurrente a una basada en líneas de trabajo que tuvieran continuidad en el tiempo.

Esto fue algo en el que me involucraron aún sin tener mucho contexto junto al resto de managers de tech y producto, en parte venía bien tener a alguien con mirada limpia aunque en ocasiones pudiera pecar de ingenuo, para cuestionar supuestos y detectar disonancias.

En aquel entonces me resultó muy útil que alguna de la gente involucrada en la reorganización estuviera hablando en términos de Team Topologies, porque nos ayudaba a tener un lenguaje común. Eso lo terminamos enfrentando con un ejercicio de Context Mapping (en un par de eventos charlé sobre ello), donde representamos buena parte del funcionamiento de la compañía para ver el encaje de equipos respecto a la situación actual.

Este ejercicio sirvió para completar la foto real a la que íbamos, e incluso permitió detectar potenciales problemas de bounded contexts en los que había muchas manos y algunas en las que había muy pocas. Así que cuando con el paso del tiempo surgieron algunos problemas relacionados, no nos pilló tan por sorpresa.

Además, institucionalizamos el dar seguimiento a lo que surgía de las retros de los equipos, ya que se estableció como práctica que se documentase por escrito al menos lo más destacado de ellas y las acciones que surgieran. Esta práctica se mantiene a día de hoy, y resulta muy útil a la capa de management como complemento a los 1:1s para detectar fricciones y puntos de mejora.

Mucho de esto y algunas cosas más, las compartí en la charla Desarrollo de producto en una Scale-Up precisamente en la Pamplona Crafters 2024.

Foto donde hay algo más de 100 personas de pie posando para la foto, fondo con árboles y suelo adoquinado

Volviendo a hacer producto (interno)

Tras un año, mi foco cambió a ser algo más todoterreno. Por un lado, ya tenía bastante controladas las dinámicas en el área de desarrollo de producto y a nivel de plataforma había aún puntos de mejora en los que iba trabajando, pero estábamos ya más en una fase de mejora continua y constante, además el equipo de infraestructura seguía introduciendo grandes mejoras. Mientras tanto, en otras áreas de la compañía se identificaban problemas mayores con los que creíamos que podía aportar más.

Ventas

Uno que terminó surgiendo fue en el equipo de ventas, al que había que buscarle solución de forma prioritaria, ya que ninguna de las líneas de trabajo a priori tenía foco en ese tema. Teníamos un proceso interno ineficiente y propenso a errores que terminaban sufriendo clientes High Touch de gran tamaño: muchos emails y llamadas de coordinación, uso de spreadsheets de gestión, tiempos de espera por parte de clientes y account managers, etc.

Para solventar el problema se decidió montar un squad específico moviendo a algunos perfiles técnicos desde algunas líneas de trabajo, y como no queríamos sacar de foco a product managers terminé involucrado en la fase de discovery para abordarlo.

Así que tocó entender los problemas que el equipo de ventas se estaba encontrando y, junto a compañeras de customer experience, entrevistarnos con clientes y gente del área de ventas. A partir de ahí, documentar el impacto que estaba teniendo, definir un primer alcance del MVP usando un user story map y preparar un kick-off para tener tanto al squad, stakeholders y el resto de la compañía alineados.

El squad trabajó en una herramienta que diera mayor autonomía a esos clientes de gran tamaño, permitiendo a account managers mantener el control y darles seguimiento. Y en mi caso, aunque no tiré ni una línea de código y que luego me quedase acompañando al squad de lejos casi como un stakeholder más, me lo pasé como un enano volviendo a participar en hacer producto en fases iniciales.

Creativo

Tiempo más tarde, nos encontrarnos otro problema importante en el área de creativo. Uno de los valores que ofrece Genially a las personas usuarias son las plantillas diseñadas por este equipo. Nos encontramos con un problema de atasco en la publicación de nuevas plantillas y cambios en las existentes que antaño no ocurría, el producto había evolucionado de un modo en el que terminó afectando en la operativa diaria de este equipo.

Esto es porque una vez diseñadas, existía un cuello de botella en el proceso de publicación tanto en el producto como en la web pública. Esta ineficiencia en el Go to Market provocaba tardar más tiempo en recuperar la inversión, era propenso a errores y frustraba a las personas de ese equipo.

Al final era un problema para el que la perspectiva Lean encajaba como anillo al dedo: Identificar el valor, mapear el flujo de trabajo, mantener un flujo continuo, aplicar sistema pull y buscar la mejora continua. Para lo cual se decidió crear de nuevo un squad que se enfocara en esta área.

Una vez analizado y mapeado el journey principal que queríamos resolver, habiendo identificado los distintos hand-offs y limitaciones de las herramientas, planteamos crear un nuevo backoffice diseñado para habilitar mayor autonomía y que simplificase su proceso. De ese modo podríamos sustituir de forma incremental el backoffice legacy, un CMS y un par de spreadsheets de gestión.

Para acelerar el proceso de publicación introdujimos: soporte i18n, gestión de estados, uso de IA generativa, mejoras en las validaciones… Además de crear un servicio que pudiera consumirse desde el producto y la web, cosa que evitaba el uso de herramientas externas y, a nivel técnico, simplificaba la infraestructura y la mantenibilidad futura.

Una vez eliminado ese cuello de botella, que con la combinación del trabajo del squad con el equipo creativo pasó de un retraso de 4 meses a estar al día, nos centramos en mover y mejorar el resto de procesos que se soportaban aún en el legacy en esta nueva herramienta, y en el camino colaborar con uno de los equipos de producto para introducir algunas mejoras conjuntamente.

Operaciones y tech

Aproximadamente el último año en Genially mi rol terminó pivotando de manera oficial a trabajar con foco en las operaciones internas de la compañía. Esto significaba estar en un punto medio entre tecnología, producto, negocio, organización y su potencial impacto en la operativa diaria de cualquier área de la compañía. Esto implicaba mucha amplitud y normalmente menor profundidad, mucha comunicación, intentar promover iniciativas que tuvieran sentido o frenar las que aparentemente necesitasen reflexionarse más, identificar posibles problemas entre áreas de forma prematura, moverme todavía más habitualmente entre diferentes grados de abstracción, etc.

Siempre con una perspectiva de desarrollo de producto, durante ese tiempo tuve oportunidad de trabajar de nuevo y esta vez mucho más involucrado con el área de ventas y desarrollo de negocio; además de empezar a hacerlo también con las de financiero, personas, soporte y comunidad.

Trabajando con más áreas

Con el área de ventas empezamos a trabajar en hacer crecer el MVP que arrancamos antaño, soportando nuevas casuísticas primero y luego acercando e integrando esta herramienta con el CRM que se usa en la compañía. En mi caso había estado involucrado en el día a día de la línea de trabajo que lo evoluciona, con un rol de facilitador y ocasionalmente de desatascador.

Junto a las áreas de financiero y personas hicimos pequeñas iniciativas coordinadas con líneas de trabajo de producto, aunque algunas más ambiciosas se quedaron en el tintero porque el coste de llevarlas a cabo las hacían inviables al menos en el medio plazo.

Con soporte empecé a trabajar muy de cerca, ya que había una tormenta perfecta de cambios en el producto, iteraciones de negocio, atasco en los tiempos de respuesta y degradación de la experiencia de cliente.

Lanzamos varias acciones para solventar la situación: mejorar flujos en el chatbot, rehacer la integración con la herramienta de soporte para enriquecer la información de clientes y mejorar la gestión de colas, introducir automatizaciones, contratar e integrar a un proveedor para pasar a tener un chat basado en agentes de IA que escalase sólo casos complejos, etc. Una vez recuperada una situación de normalidad pudimos entrar en un modo de mejora continua en soporte, y poder dedicar más tiempo a iniciativas relacionadas con comunidad.

Y en medio de todo esto apoyar en ajustes organizacionales, tanto a nivel de desarrollo de producto como en el resto de áreas; y en iniciativas transversales, por ejemplo y para sorpresa de nadie, últimamente con foco en un par relacionadas con IA generativa.

Foto donde aparecemos 12 personas posando de pie, sucios y con barro en el suelo tras haber estado limpiando una casa en las afueras de Álora, Málaga, tras la DANA 2025 que también afectó a esa zona

Conclusión

Aunque al inicio costó un poco ver cómo gestionar ese tipo de rol pendular en el que a veces era difícil manejar la cantidad de cambios de foco y de niveles de abstracción, se me dio siempre confianza y autonomía. Finalmente me sentí muy cómodo con ese tipo de responsabilidades.

Me permitió poder influir a nivel organizativo como un manager primero a nivel de área y luego tratar de hacerlo a nivel de compañía, aunque sin las responsabilidades de gestión de personas. Y de vez en cuando poder ejecutar trabajo directamente por ejemplo programando, documentando o investigando de forma autónoma o colaborando con más personas en equipo.

Tras tener la oportunidad de trabajar con tanta gente diferente y variedad de áreas en el contexto de una scale-up, cierro esta etapa en Genially habiendo crecido mucho profesionalmente y con un montón de aprendizajes: técnicos, organizativos, de personas, de negocio… y siendo un fan de la marca y la compañía.

Y ahora ¿qué?

Toca arrancar una aventura nueva que no esperaba, uno de esos trenes que sientes que son una gran oportunidad que tienes que tomar, pero eso lo cuento un poco más adelante en otro post.

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

Juanjo Navarro

LinkBridge, gestor de enlaces

septiembre 25, 2025 05:46

¡He creado una extensión para navegador!

Este verano, aprovechando las vacaciones, he creado una extensión para navegador que puedes utilizar si te apetece.

Se llama LinkBridge y es un gestor de enlaces para que puedas acceder fácilmente a las webs que utilizas más frecuentemente.

Te dejo un vídeo de su uso y los enlaces de descarga y después te cuento algo más sobre ella.

Algunos otros navegadores pueden usar las extensiones de Chrome o Firefox.

De dónde viene la idea

Hace tiempo que venía usando como gestor de enlaces frecuentes en el navegador el software Flame.

Software de este tipo hay mucho, algunos muy populares, pero a mi me gusta Flame por su estilo minimalista tanto en lo visual como en lo funcional.

El problema de Flame es que es una aplicación que tienes que instalar en tu propio servidor, lo cual obviamente no está al alcance de muchas personas.

Pensé que estas funciones (especialmente las que yo usaba, que no son todas) se podrían cubrir perfectamente desde una extensión del navegador que no requiriese montar nada en nuestro propio servidor.

Funciones de la extensión

Las funciones que he implementado son las principales (y las que yo uso) del software Flame:

  • Tus enlaces aparecen cada vez que abres una nueva pestaña del navegador
  • Puedes agrupar los enlaces en grupos temáticos con dos niveles: Aplicaciones (de mayor tamaño) y Bookmarks.
  • Soporte de temas, tanto claros como oscuros
  • Exportación e importación de los enlaces

Acceso al código fuente

El código fuente (por si te interesan estas cosas) está disponible en GitHub: LinkBridge en GitHub

¡Espero que te guste y te sirva si te animas a probarla!

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

Blog Bitix

Novedades y nuevas características de Java 25

septiembre 19, 2025 07:00

Habitualmente publicaba un artículo por cada versión de Java, pero teniendo en cuenta que para producción es recomendable usar preferentemente las versiones LTS estoy prefiriendo publicar uno en cada versión LTS con el acumulado de características de la versión anterior. En este caso de Java 25 como nueva LTS que sucede a Java 21.

Continuar leyendo en Blog Bitix

» 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