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

Scrum master a tiempo completo: 42 Tareas

octubre 04, 2024 08:29

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

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

Variable not found

Enlaces interesantes 579

octubre 01, 2024 06:25

Enlaces interesantes

Una semana más, comparto la recopilación de enlaces a contenidos que me han parecido interesantes.

De esta tirada, me quedo con "Las interfaces describen qué, las implementaciones describen cómo", un gran título para el artículo de Steve Smith sobre conceptos que todos deberíamos tener claros.

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI / Xamarin / Mobile

Otros

Publicado en Variable not found.

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

Variable not found

Enlaces interesantes 578

octubre 01, 2024 06:25

Enlaces interesantes

Vamos con la recopilación de enlaces de la tercera semana de septiembre, donde, como es habitual,  podemos ver un poco de todo: algunos lanzamientos, características de C#, uso de herramientas de telemetría y monitorización, rendimiento en ASP.NET Core, frontend, y más.

Como reflexión, es curioso ver que la IA está presente en cada vez más áreas del desarrollo. Y aparte, me quedo con lo poco que se suelen usar los operadores implícitos de C#, cuando realmente pueden hacer nuestro código más limpio...

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI / Xamarin

Otros

Publicado en Variable not found.

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

Variable not found

De vuelta: Enlaces interesantes 577

octubre 01, 2024 06:25

Enlaces interesantes

Tras unas semanas de merecido descanso, volvemos a la carga con el blog, inaugurando lo que, más o menos, debería ser su temporada número 18. Como de costumbre, intentaremos seguir la serie semanal de enlaces de interés y escribiendo sobre trucos, novedades y características de C#, .NET, ASP.NET Core, Blazor, JavaScript, o cualquier cosa que se ponga por delante y que considere que puede ser de utilidad para la comunidad.

Y para empezar con buen pie, lo haremos con la recopilación número 576 de enlaces que, como de costumbre, espero que os resulten interesantes. Especialmente destacable, además del lanzamiento de .NET 9 RC1, es el esperado post "Performance improvements in .NET 9" del gran Stephen Toub, todo un clásico cuando se va acercando una nueva versión del framework. Sencillamente imprescindible si queréis estar a la última.

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

.NET MAUI / Xamarin / Mobile

Publicado en Variable not found.

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

Variable not found

Registro y obtención de servicios con nombre (keyed services) en .NET

octubre 01, 2024 06:05

.NET

Como sabemos, una forma habitual de registrar servicios en el contenedor de dependencias de .NET consiste en indicar al framework la implementación de la interfaz o clase abstracta que debe ser utilizada cuando se solicite una instancia de la misma. Por ejemplo, en el siguiente código, que podría pertenecer a la inicialización de una aplicación ASP.NET Core, se registra la implementación FriendDbRepository para la interfaz IFriendRepository con un ámbito scoped o por petición:

builder.Services.AddScoped<IFriendRepository, FriendDbRepository>();

Hecho esto, podríamos solicitar una instancia de IFriendRepository en cualquier parte de nuestra aplicación que admita inyección de dependencias, como los controladores, manejadores Minimal API, otras dependencias, etc. El inyector encargará de proporcionarnos una instancia de FriendDbRepository allá donde la necesitemos:

public class FriendsController: Controller
{
    public FriendsController(IFriendRepository friendRepository)
    {
        // ... Aquí la tenemos!
    }
}

O bien, podríamos obtenerla directamente desde la colección de servicios:

public void DoSomething(IServiceProvider services)
{
    var repo = services.GetRequiredService<IFriendRepository>();
    ...
}

Como vemos en ambos casos, la única forma disponible para identificar el servicio que deseamos obtener es utilizar su tipo, o muy habitualmente, la abstracción (interfaz o clase abstracta) a la que está asociado.

¡Bienvenidos, servicios con nombre o keyed services!

En .NET 8 se añadió otra interesante posibilidad para registrar y obtener servicios desde el contenedor de dependencias: los keyed services, o servicios con nombre. Básicamente, la idea consiste en utilizar una clave o nombre en el momento de registrar el servicio, de forma que más adelante pueden solicitarse instancias usando dicho identificador.

Por ejemplo, imaginad que tenemos una aplicación que maneja estas abstracciones y clases:

interface IAnimal
{
    string SayHello();
}

public class Dog : IAnimal
{
    public string SayHello() => "Woof!";
}

public class Cat : IAnimal
{
    public string SayHello() => "Meow!";
}

Los keyed services permiten registrar ambas implementaciones de la interfaz IAnimal usando un nombre o clave para identificarlas, como en el siguiente ejemplo:

builder.Services.AddKeyedScoped<IAnimal, Cat>("gato");
builder.Services.AddKeyedScoped<IAnimal, Dog>("perro");

En primer lugar, fijaos en que hemos usado la extensión AddKeyedScoped() en lugar del tradicional AddScoped(), gracias a la cual podemos suministrar el nombre a la hora de realizar el registro.

Como podéis intuir, existen también los métodos AddKeyedSingleton() y AddKeyedTransient() si queremos registrar servicios con otros ámbitos. Por ejemplo, podríamos usar AddKeyedSingleton() para registrar dos instancias singleton con distinto nombre:

builder.Services.AddKeyedSingleton("john", new Friend("John"));
builder.Services.AddKeyedSingleton("peter", new Friend("Peter"));

En los ejemplos anteriores, los literales "gato", "perro" o "john" que hemos usado para identificar los servicios podrían haber sido cualquier otro tipo de objeto, porque, en realidad, la clave o identificador es de tipo object. La cuestión es que sean únicos e identifiquen claramente los servicios.

Una vez hemos registrado los servicios de esta forma, ya no podremos recuperarlos usando simplemente el tipo deseado; en su lugar, tendremos que indicar adicional y obligatoriamente el nombre o clave usada en su registro. La única excepción a esto es que cuando registramos un keyed service usando el valor null como clave, podremos recuperarlo usando los mecanismos habituales.

Para obtener una instancia de un servicio con nombre desde el constructor de una clase, simplemente debemos usar el atributo [FromKeyedServices] suministrándole la clave correspondiente:

public class HomeController : Controller
{
    private readonly IAnimal _animal;

    public HomeController([FromKeyedServices("gato")]IAnimal animal)
    {
        _animal = animal; // Aquí seguro que tendremos un objeto Cat
        _logger = logger;
    }
    ..
}

También podemos usar el atributo [FromKeyedServices] directamente en manejadores de Minimal API o acciones MVC:

// En Minimal APIs:
app.MapGet("/", ([FromKeyedServices("gato")] IAnimal animal) => animal.SayHello());

// En una acción de controlador:
public class PetController: Controller
{
    public string SayHello([FromKeyedServices("perro")] IAnimal animal) 
        => animal.SayHello();
}

El sistema usará tanto el tipo del parámetro como la clave para determinar el servicio que debe ser retornado. Si no se encuentra, retornará un valor nulo.

De la misma forma, podemos obtener un servicio con nombre desde la colección de servicios usando el método GetKeyedService():

public void DoSomething(IServiceProvider services)
{
    // Devolverá un nulo si no existe:
    var gato = services.GetKeyedService<IAnimal>("gato");

    // O bien, se lanza excepción si no existe:
    var perro = services.GetRequiredKeyedService<IAnimal>("perro");
    ...
}

En definitiva, se trata de un mecanismo muy interesante y que puede ayudarnos a simplificar algunos escenarios, que antes nos veíamos obligados a solucionar usando factorías o implementando interfaces específicas para cada clase.

¡Espero que os resulte útil! 

Publicado en Variable not found.

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

Variable not found

Novedades de System.Text.Json en .NET 9

septiembre 24, 2024 06:05

.NET

Acercándose el lanzamiento de .NET 9 el próximo mes de noviembre, podemos ver ya algunas de las novedades que traerá la nueva versión, con las que podemos jugar desde hace algunos meses instalando las previews que van apareciendo cada mes.

En esta ocasión vamos a ver algunas novedades más interesantes que se han añadido a la biblioteca de serialización JSON oficial, conocida por todos como System.Text.Json:

¡Vamos a ello!

Nota: Este artículo está basado en .NET 9 RC1, por lo que algunas de las características descritas podrían cambiar en la versión final.

1. Opciones de personalización de la indentación

Hasta .NET 8, las opciones de personalización relativas al indentado de JSON generado era bastante limitada. De hecho, sólo podíamos decidir si lo queríamos indentar o no usando la propiedad WriteIndented de JsonOptions:

var obj = new
{
    Name = "John",
    Age = 30,
    Address = new { Street = "123 Main St", City = "New York" }
};

var jsonOptions = new JsonSerializerOptions()
{
    WriteIndented = true, // Queremos indentar el JSON
};

Console.WriteLine(JsonSerializer.Serialize(obj, jsonOptions));

El resultado será siempre un JSON indentado a dos espacios como el siguiente:

{
  "Name": "John",
  "Age": 30,
  "Address": {
    "Street": "123 Main St",
    "City": "New York"
  }
}

En .NET 9 disponemos de dos nuevas propiedades para personalizar la indentación del JSON generado. La propiedad IndentCharacter permite especificar el carácter a utilizar (espacio o tabulador, exclusivamente), y mediante IndentSize podemos indicar el número de caracteres a utilizar en cada nivel de indentación.

var jsonOptions = new JsonSerializerOptions()
{
    WriteIndented = true,
    IndentCharacter = '\t',
    IndentSize = 2
};

Console.WriteLine(JsonSerializer.Serialize(obj, jsonOptions));

En este caso, el resultado será así (2 tabuladores por nivel de indentación):

{
                "Name": "John",
                "Age": 30,
                "Address": {
                                "Street": "123 Main St",
                                "City": "New York"
                }
}

2. Singleton de opciones de serialización y deserialización para la web

ASP.NET Core utiliza una configuración por defecto para serializar y deserializar objetos JSON, que ahora está disponible de forma pública en la propiedad JsonSerializerOptions.Web.

El objeto retornado es un singleton JsonSerializerOptions de sólo lectura, que estará disponible en cualquier punto de la aplicación.

Por defecto, este objeto está configurado de la siguiente manera:

  • PropertyNameCaseInsensitive está establecido a true, por lo que la deserialización de propiedades es insensible a mayúsculas y minúsculas.
  • JsonPropertyNamingPolicy tiene el valor JsonNamingPolicy.CamelCase, así que las propiedades se serializan en formato camelCase, el habitual en JavaScript y JSON.
  • NumberHandling es JsonNumberHandling.AllowReadingFromString, así que será posible deserializar números que vengan especificados como texto.

Un ejemplo de utilización de este objeto sería el siguiente:

var obj = new
{
    Name = "John",
    Age = 30,
    Address = new { Street = "123 Main St", City = "New York" }
};

Console.WriteLine(JsonSerializer.Serialize(obj, JsonSerializerOptions.Web));

// Resultado:
// {"name":"John","age":30,"address":{"street":"123 Main St","city":"New York"}}

Dado que el objeto es de sólo lectura, no podemos modificar sus propiedades. Si necesitásemos algún tipo de cambio en la configuración, podríamos crear una configuración nueva partiendo de él, e introducir las modificaciones deseadas, por ejemplo:

var jsonOptions = new JsonSerializerOptions(JsonSerializerOptions.Web)
{
    WriteIndented = true,
    IndentCharacter = '\t',
    IndentSize = 2
};

3. Soporte de anotaciones de anulabilidad

En .NET 8 y versiones anteriores, System.Text.Json no respetaba las anotaciones de anulabilidad de C# en las propiedades de los tipos de referencia. Por ejemplo, si tenemos una propiedad de tipo referencia que no puede ser nula como en el siguiente caso, podemos ver que el siguiente código deserializará sobre ella un valor nulo sin problema:

var myFriend = JsonSerializer.Deserialize<Friend>("""{ "Name": null }""");
Console.WriteLine(myFriend.Name ?? "Unknown"); // Muestra "Unknown"

// Friend tiene un campo "Name" que no puede ser nulo
public record Friend (string Name);

A partir de .NET 9, podemos indicar opcionalmente a System.Text.Json que respete la anulabilidad de propiedades, es decir, si una propiedad no es anulable, al deserializarla no podremos establecerla al valor nulo.

Esto podemos conseguirlo simplemente estableciendo a true la propiedad RespectNullableAnnotations de las opciones de deserialización:

var opt = new JsonSerializerOptions() { RespectNullableAnnotations = true };
var myFriend = JsonSerializer.Deserialize<Friend>("""{ "Name": null }""", opt);
Console.WriteLine(myFriend.Name ?? "Unknown"); // Lanza una excepción

Según la documentación, otra posibilidad es hacerlo de forma global para todo el proyecto, añadiendo la siguiente configuración en el archivo .csproj:

<ItemGroup>
  <RuntimeHostConfigurationOption 
     Include="System.Text.Json.JsonSerializerOptions.RespectNullableAnnotations" 
     Value="true" />
</ItemGroup>

Supongo que, debido a que aún estamos jugando con versiones preview del compilador, esta última opción no conseguí que me funcionara.

Otra cosa que he visto curiosa es que el siguiente código, a mi entender, debería lanzar una excepción, pero no lo hace:

var opt = new JsonSerializerOptions() { RespectNullableAnnotations = true };

var myFriend = JsonSerializer.Deserialize<Friend>("{ }", opt);
Console.WriteLine(myFriend.Name ?? "Unknown"); // Muestra "Unknown"

En principio, si la propiedad Name hemos dicho que no era anulable, ¿no debería lanzar una excepción al deserializar un objeto que no especifica su valor? Pues no, y parece ser que se trata de un comportamiento esperado; hay un interesante hilo al respecto en GitHub discutiendo el por qué de esta decisión, aunque en el siguiente apartado veremos que existe en algunos casos existe una forma alternativa de evitar esta situación.

Por último, la propiedad RespectNullableAnnotations también afecta a la serialización, de forma que si una propiedad no anulable tiene un valor nulo al ser serializada, se lanzará una excepción:

var opt = new JsonSerializerOptions() { RespectNullableAnnotations = true };

var myFriend = new Friend(null);
Console.WriteLine(JsonSerializer.Serialize(myFriend, opt)); // Lanza una excepción

4. Comprobación de parámetros obligatorios del constructor

En .NET 8 y anteriores, los parámetros del constructor del tipo a deserializar eran tratados como siempre como opcionales. Por esta razón, el código siguiente no provoca errores:

var myFriend = JsonSerializer.Deserialize<Friend>("""{ }""");
Console.WriteLine(myFriend.Name ?? "Unknown"); // Muestra "Unknown"

public record Friend(string Name);

En .NET 9, es posible indicar al deserializador que queremos respetar los parámetros requeridos del constructor, de forma que si no pueden ser satisfechos se lanzará una excepción. Esto se consigue con el nuevo flag RespectRequiredConstructorParameters en las opciones de deserialización:

var opt = new JsonSerializerOptions() { RespectRequiredConstructorParameters = true };

var myFriend = JsonSerializer.Deserialize<Friend>("""{ }""", opt);
Console.WriteLine(myFriend.Name ?? "Unknown"); // Lanza una excepción

La excepción, de tipo JsonException es bastante clara en su texto de descripción: 'JSON deserialization for type 'Friend' was missing required properties including: 'Name'.'.

Como en el caso anterior, este comportamiento puede ser también configurado de forma global para todo el proyecto, añadiendo la siguiente configuración en el archivo .csproj:

<ItemGroup>
  <RuntimeHostConfigurationOption 
      Include="System.Text.Json.JsonSerializerOptions.RespectRequiredConstructorParameters" 
      Value="true" />
</ItemGroup>

Y como en el caso anterior, tampoco he conseguido que me funcione de esta forma 😆 Esperemos que las siguientes preview o la versión final lo solucionen.

5. Descripción de tipos .NET usando JSON Schema

La nueva clase estática JsonSchemaExporter expone el método GetJsonSchemaAsNode(), que permite obtener el esquema JSON de un tipo .NET en forma de objeto JsonNode.

Su uso es muy sencillo, simplemente pasamos las opciones a utilizar para serializar el esquema, y el tipo del que queremos obtenerlo. Observad el siguiente ejemplo:

var schema = JsonSchemaExporter.GetJsonSchemaAsNode(
    JsonSerializerOptions.Default, 
    typeof(Friend)
);
Console.WriteLine(schema);

public record Friend(string Name, string? nickName, int Age = 20);

El resultado que obtendremos es una descripción del tipo, siguiendo el estándar JSON Schema, que en este caso sería algo así:

{
  "type": [
    "object",
    "null"
  ],
  "properties": {
    "Name": {
      "type": "string"
    },
    "nickName": {
      "type": [
        "string",
        "null"
      ]
    },
    "Age": {
      "type": "integer",
      "default": 20
    }
  },
  "required": [
    "Name",
    "nickName"
  ]
}

Conclusión

En este artículo hemos visto algunas de las novedades que traerá la nueva versión de .NET 9 en la biblioteca de serialización JSON oficial, System.Text.Json. Aunque no son cambios revolucionarios, sí que son mejoras que facilitarán la vida a los desarrolladores que trabajamos con JSON en nuestras aplicaciones.

¡Espero que os haya resultado interesante!

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

Picando Código

Star Wars: A New Hope en concierto

septiembre 22, 2024 09:39

Star Wars: A New Hope en concierto en Usher Hall, Edimburgo

El pasado viernes 20 de setiembre de 2024, se realizó en el Usher Hall de la ciudad de Edimburgo el evento “Star Wars: A New Hope in concert”. En este evento la Orquesta Nacional de Escocia, conducida por Ben Palmer, ejecuta la música de John Williams en simultáneo con la película. ¡Fue una experiencia inolvidable!

Desde el momento que apareció el logo de 20th Century Fox y escuché la tan familiar percusión tocada en vivo, me recorrió una emoción enorme y se me erizaron todos los pelos de la nuca. Fue lo más parecido que puedo tener a la experiencia de mirar Star Wars por primera vez. Como he dicho antes, Star Wars: A New Hope debe ser la película que miré más veces en mi vida. Pero disfrutarla en un lugar como Usher Hall acompañada de estos músicos espectaculares tocando cada nota de la película, me voló la cabeza.

La música de John Williams es uno de los protagonistas principales de Star Wars. Y la Orquesta Nacional de Escocia la hace perfecta, no falta nada. El evento se hace relativamente seguido, recuerdo haber visto los afiches otros años y habérmelo perdido porque ya se habían vendido todos los asientos decentes. Pero ya estoy en la lista de distribución de noticias, así que soy de los que compran entradas temprano cuando aparece algo. También hacen eventos con otras películas y uno de videojuegos (al que tuve el gusto de asistir este año también), y música clásica, así que hay orquesta para rato. Ojalá tengan planeado hacer The Empire Strikes Back y The Return of the Jedi eventualmente ¡estoy ahí!

Durante la escena de Jabba y Han Solo en Tatooine, mi mente empezó a divagar. Como tantos nerds que miramos los documentales y leímos sobre los cambios que hizo Lucas en las ediciones especiales de 1997 sabemos: originalmente Jabba era un actor humano en una escena que no llegó al corte final. En las versiones nuevas se agregó a Jabba con gráficos en computadora, así como el tosco (desprolijo, horrible) efecto de Han pisándole la cola. Este efecto se ve bastante mal todavía. Así que pensaba si con los gigallones de dólares que tiene Disney, no sería hora de re-editar la trilogía original en versión “desespecializada”. O en el peor de los casos, una versión re-especializada donde corrije las cosas malas de la versión especializada original…

Existen versiones des-especializadas no oficiales creadas por la comunidad, si uno sabe dónde encontrarlas. Pero me parece que hay potencial para un boxset nuevo en Blu-Ray HD 4K Mega 64 sin las “mejoras” de 1997 (yo lo compro 🙋).

No tengo palabras para describir lo alucinante que fue el espectáculo, disfruté cada momento de la película como nunca antes la había disfrutado. Con la escena de la ceremonia final donde Leia le da las medallas a Han y Luke (¡spoiler!) la música va creciendo en fuerza hasta el punto más alto de impacto en la transición hacia los créditos. En este momento el público explotó en merecido aplauso y festejo. La mayoría de los asistentes nos quedamos hasta que terminaron los créditos, disfrutando las últimas notas de la noche y aplaudiendo a la orquesta por tal impresionante actuación.

El Usher Hall como ven en la foto es uno de esos teatros espectaculares diseñados con terrible acústica. Este año fue la primera vez que lo visité en otro evento de la Orquesta Nacional de Escocia, uno con música de videojuegos, y fue igualmente disfrutable (aunque ahí aprendí que es mejor sentarse en los asientos de los niveles altos para ver mejor los músicos). Si tienen la oportunidad de ver un evento de este tipo, lo recomiendo mucho. Por mi parte, quedo esperando más idas al Usher Hall a ver la Sinfónica. Ya veo que hay un evento de “La música de John Williams” en 2025…

El post Star Wars: A New Hope en concierto fue publicado originalmente en Picando Código.

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

Picando Código

Simular botón del medio en mouse 8bitdo N30 en Linux

septiembre 17, 2024 11:00

Desde hace un tiempo soy el feliz poseedor de un mouse N30 de 8BitDo, o “el mouse NES” como le digo yo. El mouse es un homenaje al Nintendo Entertainment System, y usa el mismo tipo de botones y paleta de colores. Sinceramente es más “lindo” que “cómodo”, pero al final del día es un mouse, y no uso tanto el ratón a la hora de programar (para cosas como juegos o diseño, más vale usar otro más ergonómico).

Cuenta con los dos botones tradicionales y la superficie entre medio sirve para hacer scroll, a pesar de no tener ninguna indicación visual. Es raro, pero hace scroll, y también podemos usar el d-pad a la izquierda pero el movimiento es un poco más “robótico”. Algo que extrañaba es el botón del medio del mouse, que uso mucho para cerrar pestañas, arrastrar la pantalla en GIMP, o abrir enlaces en pestaña nueva, entre otras interacciones. Por defecto, presionar los dos botones a la vez no simulaba el botón del medio en mi sistema, así que tuve que investigar el tema.

Mouse 8bitdo NES

Mouse 8bitdo NES – Picando Código recomienda lavarse las manos antes de tocar el mouse o controles después de haber comido golosinas…

Encontré que con la herramienta xinput podemos tanto detectar el mouse como cambiar las características habilitadas. Al correr xinput list en mi consola, obtengo la lista de dispositivos:

$ xinput list
xinput list
⎡ Virtual core pointer                          id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ DELL0820:00 044E:121F Mouse               id=11   [slave  pointer  (2)]
⎜   ↳ DELL0820:00 044E:121F Touchpad            id=12   [slave  pointer  (2)]
⎜   ↳ Keychron K8 Keychron K8                   id=19   [slave  pointer  (2)]
⎜   ↳ MOSART Semi. 2.4G Keyboard Mouse Consumer Control id=22   [slave  pointer  (2)]
⎜   ↳ MOSART Semi. 2.4G Keyboard Mouse          id=25   [slave  pointer  (2)]
⎣ Virtual core keyboard                         id=3    [master keyboard (2)]
   ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
   ↳ Power Button                              id=6    [slave  keyboard (3)]
   ↳ Video Bus                                 id=7    [slave  keyboard (3)]
   ↳ Video Bus                                 id=8    [slave  keyboard (3)]
   ↳ Power Button                              id=9    [slave  keyboard (3)]
   ↳ Sleep Button                              id=10   [slave  keyboard (3)]
   ↳ DELL0820:00 044E:121F UNKNOWN             id=13   [slave  keyboard (3)]
   ↳ Intel HID events                          id=14   [slave  keyboard (3)]
   ↳ Intel HID 5 button array                  id=15   [slave  keyboard (3)]
   ↳ Dell WMI hotkeys                          id=16   [slave  keyboard (3)]
   ↳ AT Translated Set 2 keyboard              id=17   [slave  keyboard (3)]
   ↳ Keychron K8 Keychron K8                   id=18   [slave  keyboard (3)]
   ↳ Keychron K8 Keychron K8                   id=20   [slave  keyboard (3)]
   ↳ MOSART Semi. 2.4G Keyboard Mouse System Control   id=21   [slave  keyboard (3)]
   ↳ MOSART Semi. 2.4G Keyboard Mouse Consumer Control id=23   [slave  keyboard (3)]
   ↳ MOSART Semi. 2.4G Keyboard Mouse          id=24   [slave  keyboard (3)]

Tiene pinta que es MOSART Semi. 2.4G Keyboard Mouse id=25. Pasándole el nombre a xinput, podemos ver qué propiedades tiene:

$ xinput list-props ‘pointer:MOSART Semi. 2.4G Keyboard Mouse’
Device ‘MOSART Semi. 2.4G Keyboard Mouse’:
       Device Enabled (215):   1
       Coordinate Transformation Matrix (217): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000
, 0.000000, 1.000000
       libinput Natural Scrolling Enabled (352):       0
       libinput Natural Scrolling Enabled Default (353):       0
       libinput Scroll Methods Available (354):        0, 0, 1
       libinput Scroll Method Enabled (355):   0, 0, 0
       libinput Scroll Method Enabled Default (356):   0, 0, 0
       libinput Button Scrolling Button (357): 2
       libinput Button Scrolling Button Default (358): 2
       libinput Button Scrolling Button Lock Enabled (359):    0
       libinput Button Scrolling Button Lock Enabled Default (360):    0
       libinput Middle Emulation Enabled (361):        1
       libinput Middle Emulation Enabled Default (362):        0
       libinput Accel Speed (363):     1.000000
       libinput Accel Speed Default (364):     0.000000
       libinput Accel Profiles Available (365):        1, 1
       libinput Accel Profile Enabled (366):   1, 0
       libinput Accel Profile Enabled Default (367):   1, 0
       libinput Left Handed Enabled (368):     0
       libinput Left Handed Enabled Default (369):     0
       libinput Send Events Modes Available (337):     1, 0
       libinput Send Events Mode Enabled (338):        0, 0
       libinput Send Events Mode Enabled Default (339):        0, 0
       Device Node (340):      “/dev/input/event20”
       Device Product ID (341):        1578, 16641
       libinput Drag Lock Buttons (370):       <no items>
       libinput Horizontal Scroll Enabled (371):       1
       libinput Scrolling Pixel Distance (372):        15
       libinput Scrolling Pixel Distance Default (373):        15
       libinput High Resolution Wheel Scroll Enabled (374):    1

La propiedad de interés es Middle Emulation Enabled, que tiene el valor 0. Para emular el botón del medio, cambio el valor a 1 con:

$ xinput set-prop ‘pointer:MOSART Semi. 2.4G Keyboard Mouse’ ‘libinput Middle Emulation Enabled’ 1

Ahora el tema es hacer que esto se ejecute automáticamente cada vez que inicio el sistema. En esta computadora estoy usando KDE Neon con KDE, así que me metí en las configuraciones del sistema, System > Autostart, y agregué una entrada manual. En “Program” o “Programa” ingresé xinput y en “Arguments” set-prop 'pointer:MOSART Semi. 2.4G Keyboard Mouse' 'libinput Middle Emulation Enabled' 1. Esto agrega un archivo .desktop a ~/.config/autostart y si el mouse está conectado al iniciar el sistema, todo va bien. Si conecto el mouse más tarde, puedo ejecutar el comando a mano desde ese mismo menú.

Y así quedó funcionando la emulación de botón del medio con los dos botones del mouse.

El post Simular botón del medio en mouse 8bitdo N30 en Linux fue publicado originalmente en Picando Código.

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

Variable not found

No se puede conectar al servidor web 'https', el servidor web ya no funciona y otras pistas de que no has lanzado correctamente tu aplicación ASP.NET Core

septiembre 17, 2024 06:05

ASP.NET Core

Una pregunta que me hacen con cierta frecuencia los alumnos de mi curso de ASP.NET Core en CampusMVP es que por qué, al ejecutar una aplicación de este tipo, Visual Studio les muestra un mensaje como el siguiente, no se lanza el navegador y no pueden acceder a la aplicación:

Ventana de error con mensaje: No se puede conectar al servidor web 'https'. El servidor webya no funciona

Generalmente la respuesta es bastante sencilla: Visual Studio nos está informando de que el servidor web no ha sido lanzado al ejecutar la aplicación.

Dado que esta cuestión siempre llega procedente de alumnos que recién están comenzando el curso y están haciendo sus primeros pinitos con ASP.NET Core, middlewares y tocando el código de inicialización, el motivo suele ser un despiste o un pequeño lío con las llamadas al método app.Run().

En ASP.NET Core se usa app.Run() tanto para insertar middlewares finales en el pipeline (si se usa con parámetros) como para lanzar el servidor web y dejarlo a la escucha de peticiones (si se hace sin parámetros). Desde luego es una decisión discutible, pero bueno, es lo que tenemos. La cuestión es que esto puede llevar a confusión, porque si no se llama a app.Run() (sin parámetros), el servidor web no se iniciará.

Por tanto, si os encontráis con este problema, revisad vuestro código de arranque y aseguraos de que estáis llamando a app.Run() al final del código de inicialización:

var builder = WebApplication.CreateBuilder(args);
... // Otro código de inicialización

app.Run(); // ¡No olvidéis esta línea!

Otros síntomas del mismo problema

En Visual Studio, aparte del popup de error que hemos visto anteriormente, el problema puede manifestarse de otras formas, como en un mensaje de error algo más escueto, pero más o menos en la misma línea:

Ventana de error con mensaje: Unable to connect to web server 'https'

También podemos verlo en la ventana "Output" de Visual Studio, donde se nos informa de que la aplicación se ha detenido, o un mensaje de error en el pie de la ventana:

Ventana de salida de Visual Studio mostrando que la aplicación ha finalizado, y mensaje en el pie indicando que el servidor no pudo iniciar

Asimismo, si observamos la ventana de consola que suele abrirse al ejecutar la aplicación desde Visual Studio, veremos que ésta se ha detenido:

C:\Projects\MyAspNetCoreApp\myAspNetCoreApp.exe (process 13400) exited with code 0 (0x0).
To automatically close the console when debugging stops, enable 
Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .

Por último, si en lugar de Visual Studio usamos directamente la línea de comandos, podemos verlo también muy claramente. Basta con ejecutar el proyecto desde la línea de comandos con dotnet run y veremos que se detiene inmediatamente:

C:\Projects\MyAspNetCoreApp>dotnet run
Building...

C:\Projects\MyAspNetCoreApp>_

¡Espero que os sea de utilidad!

Publicado en Variable not found.

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

Picando Código

Veranos con Zelda: The Legend of Zelda – A Link to the Past

septiembre 15, 2024 09:55

The Legend of Zelda: A Link to the Past

En Escocia, el invierno no avisa, y ya hay días que está empezando a hacer frío. Parece que el verano es junio, julio y agosto, y en setiembre nos vamos preparando para prender la calefacción y abrigarnos más… Para no aceptar del todo que el verano terminó, qué mejor que escribir sobre Zelda.

Gran parte de los títulos de The Legend of Zelda que he jugado, los asocio con el verano. En general esto no viene relacionado a la fecha de salida del juego. Simplemente coincide que en mi memoria las aventuras de Link en Hyrule (y otros mundos) están atadas al calor y estar afuera. Entre ellos se incluye jugar Link’s Awakening en el patio para agarrar buena luz en el Game Boy o que me prestaran un Nintendo 64 un verano y recorrer Hyrule en 3D en Ocarina of Time con la ventana de mi cuarto abierta.

Este verano del hemisferio norte, con la inminente salida de The Legend of Zelda: Echoes of Wisdom, decidí resolver uno de mis asuntos pendientes en videojuegos. Tengo el cartucho original de The Legend Of Zelda: A Link to the Past en alguna caja en Uruguay con todos mis juegos de Super Nintendo. Pero a pesar de haber empezado varias veces esa aventura, nunca la terminé. También la empecé de nuevo cuando adquirí mi SNES Classic Mini, y tampoco la terminé ahí. Disponible ahora en Nintendo Switch Online, me dispuse a resolver este problema…

El principio del juego me resultó muy familiar, de esperar visto que lo he empezado varias veces. La experiencia 2D de Zelda se ha mantenido similar a lo largo de los años. Los últimos del estilo que había jugado al momento habían sido la remake de Link’s Awakening para Switch (y sinceramente cada tanto juego a la versión DX de Game Boy Color), y un buen tiempo antes A Link Between Worlds en 3DS.

Me llevó jugar unos pocos minutos para darme cuenta por qué nunca había terminado este juego: No me engancha… La introducción está bien como para mandarte de lleno en una aventura. No demoramos mucho en entender qué tenemos que hacer y ya salimos a buscar a la princesa Zelda desde un principio. Por alguna razón me costó entrarle, no me gusta demasiado el inicio.

Hay otro tema en particular que me molestaba bastante. Como la mayoría de los Zeldas, tiene ese aspecto “metroidvaniaesco” donde empezamos con pocos poderes o ítems. Con el tiempo descubrimos ítems y corazones que nos dan más vida, por lo que resulta más difícil morir y más fácil derrotar distintos enemigos. Durante las primeras horas, me resultó molesto lo débil que era Link y lo fácil que era morir. Tenemos enemigos atacando a Link prácticamente todo el tiempo cuando andamos explorando Hyrule, y esto al principio me irritaba porque no había tenido tiempo de agarrarle la mano al combate.

The Legend Of Zelda: A Link to the PastAlgo importante que encontraba particularmente negativo es el uso de la espada. Creo que incluso en comparacion con Link’s Awakening en Game Boy, el rango de ataque con la espada es un poco raro. Pasadas varias horas me terminé acostumbrando y ya no sería un problema. Pero me costó, e incluso hacia el final donde con más experiencia acostumbraba a vencer a los enemigos con el ataque a distancia de la Master Sword, seguía pareciendo raro. Y una forma que podría describir el problema es que los enemigos atacan desde cualquier ángulo, mientras que el ataque de la espada sólo se puede hacer en 4 direcciones, vertical u horizontal.

Link’s Awakening vino un poco después, así que tiene sentido que hayan mejorado éstos aspectos. En mi mente el de Super Nintendo “tenía que ser mejor” que el de Game Boy. Pero estos ajustes son cosas que van evolucionando con el tiempo a lo que se aprende qué funciona mejor con el control. El punto de referencia que tenían hasta ahí eran los dos primeros juegos en el NES.

El escudo es casi inútil. Esto es otro aspecto que lo comparaba con Link’s Awakening, y me parecía “peor” en Super Nintendo. En el primero, si apreto B y mantengo el escudo en alto, casi nada daña a Link (¿si recuerdo bien?). En éste, el escudo está en alto por defecto, y depende del ángulo en que nos ataquen a distancia si el ataque nos daña o no. Más adelante es importante dominar la posición del escudo mientras mantenemos la espada “cargando” (cosa de poder caminar en cualquier dirección mientras Link mantiene el punto de vista y el escudo fijos) para evitar ciertos ataques en calabozos.

Tras agarrarle la mano a estos detalles, y obtener más ítems que amplían el rango de ataques que podemos hacer con Link, se hace más llevadero.

La música es genial. Esto es característico en la Leyenda de Zelda, y se destaca en A Link to the Past. Me imagino en su momento debe haber sido bastante especial venir del NES y escuchar el tema principal de Zelda un poco más “orquestrado” gracias al sistema de sonido más avanzado del Super Nintendo. Particularmente en los calabozos está muy buena, y suma mucho a la ambientación como opresiva y tenebrosa cuando corresponde.

Los primeros jefes me resultaron más complicados que los que se van encontrando hacia el final. Eventualmente es cuestión de aprenderse los patrones de ataque para poder esquivarlos, y encontrar su punto débil. Algunos caen en la categoría de tediosos y frustrantes, aunque una vez que encontramos ese patrón, no son tan difíciles de vencer.

Los gráficos no son nada del otro mundo, pero están muy bien para los 16 bits de la época. El pixelart envejeció muy bien, a veces 16 bits es todo lo que necesitamos. Se nota que aprovecharon también el “Mode 7” del Super Nintendo, el modo gráfico que permite rotar y escalar capas para dar la impresión de 3D y otros efectos. Los cartuchos desarrollados por Nintendo en el nuevo sistema tenían que hacer demostración técnica de lo nuevo que traía el Super Nintendo.

Los puzzles y calabozos están entretenidos, típicos de lo que acostumbra a ofrecer Zelda. La historia por más que Nintendo no le de demasiada importancia, hace su trabajo de transportarnos un poco e interesarnos por los personajes que habitan este mundo pixelado, con la satisfacción final de haberles ayudado a derrotar al mal y devolver la paz a Hyrule. Estaría interesante volver a jugar la secuela A Link Between Worlds ahora. Tiene el mismo mapa y concepto de dos mundos paralelos con todos los años de mejoras encima y lo disfruté mucho cuando lo jugué.

Para mí A Link to the Past no es uno de los mejores títulos de la saga. Creo que gran parte de la experiencia para quienes así lo consideran, se define por cuándo lo jugaron además de las experiencias que hayan tenido previamente con otros juegos y demás. Yo lo terminé todos estos años después, habiendo pasado por varios títulos que vinieron después e incorporaron cosas que de repente eran innovación en A Link To The Past. Me alegro de haberlo jugado y conocer la historia de esta entrega en la leyenda de Zelda. Si bien no es de mis favoritos, igual lo disfruté.

Por ahora hay un sólo juego de Zelda que puedo decir que me frustró al punto de considerarlo definitivamente “el peor Zelda”, pero eso fue un verano distinto y un post para otro día…

The Legend of Zelda: A Link to the Past

El post Veranos con Zelda: The Legend of Zelda – A Link to the Past fue publicado originalmente en Picando Código.

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

Picando Código

¡Feliz día del programador!

septiembre 12, 2024 04:00

¡Feliz día del programador!

¡Feliz día del programador! Hoy 12 de setiembre es el día número 256 (28) del año por ser la cantidad de valores representables en un byte de datos (13/9 en los años comunes y 12/9 años bisiestos). Por esto se festeja el día del programador. Como es tradición en el blog, escribo un post en principio deseando feliz día a todos los programadores y las programadoras que lo lean, y les pregunto: ¿en qué andan? ¿qué lenguajes o tecnologías nuevas están usando este año?

Haciendo un repaso en mi caso se repite bastante lo que dije el año pasado. Pero puedo agregar que estuve haciendo un poco más de desarrollo de videojuegos. En ese momento estaba aprendiendo Godot, pero me metí también un poco con DragonRuby y he estado jugando con algunas otras herramientas relacionadas. Con suerte en algún momento tenga más para compartir y siga aprendiendo de estos temas que tanto me interesan.

En el trabajo estoy por cumplir 5 años en breve. Sigo haciendo cosas con Ruby, bash y PHP. Hay una cantidad de trabajo regular que vengo haciendo desde que empecé, pero siempre se van agregando cosas y proyectos nuevos por hacer, cosa de no aburrirse.

El año pasado comentaba que me compré una Raspberry Pi 4, y empecé a armarme servidores locales para cosas divertidas. Espero en algún momento sentarme a escribir al respecto para compartir lo aprendido, lo hecho, y para no olvidarme en el futuro. Para tener como referencia, la cantidad de posts en estado “Borrador” ha subido a 331 en este momento en el blog. ¡Con suerte el año que viene bajo a menos de 300!

Este año seguramente vaya a mi primera conferencia Ruby en años. ¡Vuelven las conferencias Ruby a Escocia! Después de las últimas dos Scottish Ruby Conf en 2013 y 2014 (a las que tuve el gusto de asistir), se viene Haggis Ruby en Octubre. Va a ser en Edimburgo, la ciudad donde vivo, así que ahí estaré. A pesar de que mi ansiedad social ha aumentado exponencialmente desde el 2020, tengo muchas ganas de volver a una conferencia Ruby. La comunidad y las conferencias solían ser una de las cosas que más disfrutaba del entorno profesional, pero por distintas razones no he ido a tantas en los últimos tiempos.

No mucho más para comentar, por lo menos no en lo que respecta a programación. Pero acá andamos todavía.

El día del programador otros años en este blog: 2007200820092010201120122013201420152017201820192023

El post ¡Feliz día del programador! fue publicado originalmente en Picando Código.

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

Una sinfonía en C#

Docker tricks, crear una imagen para poder depurar un error.

septiembre 10, 2024 12:00

“Introducción”

En este caso queremos crear una imagen pero nos da algún tipo de error, y es complicado de resolver. Bueno, lo que podemos hacer es apuntar los comandos que queremos ejecutar, crear una imagen con su base y hasta el punto que funciona y hacer que inicie con un comando que nos permita crear al contenedor e ingresar.

Crear imagen a partir de una con problemas

FROM node:20.12.0 AS builder
ARG environment=dev

WORKDIR /app
COPY ./package.json /app/
COPY ./yarn.lock /app/

RUN yarn
COPY . /app/
RUN yarn build:$environment

FROM nginx:1.21.5-alpine

EXPOSE 80/tcp
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /app/dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]

y vemos que nos da un error al hacer RUN yarn

¿Qué podemos hacer?

Facil, creamos una imagen con la base que tenemos y hasta el punto que funciona, y luego la ejecutamos con un comando que nos permita ingresar al contenedor. Pero como comando de inicio, usamos tail -f /dev/null para que se quede esperando y no se cierre.

FROM node:20.12.0 AS builder
ARG environment=dev

WORKDIR /app
COPY ./package.json /app/
COPY ./yarn.lock /app/

CMD ["tail", "-f", "/dev/null"]

una vez hecho esto, podemos hacer un docker build -t myimage . y luego un docker run -it myimage /bin/bash para ingresar al contenedor y ver que es lo que pasa.

Desde dentro del container ejecutamos el comando que da problemas y vemos el error que nos da.

yarn

.....

Request failed \"401 Unauthorized\""

Y vemos que nos da un error al intentar restaurar los paquetes.

Nada más, una forma sencilla de ir depurando error por error dentro de un contenedor.

Agregamos una línea para copiar el archivo de configuración de npm y listo.

FROM node:20.12.0 AS builder
ARG environment=dev

WORKDIR /app
COPY ./package.json /app/
COPY ./yarn.lock /app/
COPY .npmrc /app/ # <-- Agregamos esta línea

RUN yarn
COPY . /app/
RUN yarn build:$environment

FROM nginx:1.21.5-alpine

EXPOSE 80/tcp
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /app/dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]

Nos leemos.

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

Picando Código

Turrican III (Amiga) y Mega Turrican (Sega Genesis/Mega Drive)

septiembre 05, 2024 05:01

Turrican III Amiga - Mega Turrican Sega Genesis/Mega Drive

Siguiendo con los Turrican en orden cronológico, jugué Turrican III, seguido de Mega Turrican. Como comentaba en el post anterior, se trata del mismo juego para dos plataformas distintas. Factor 5 desarrolló primero Mega Turrican para Sega Genesis/Mega Drive, y después hizo un port para Amiga y lo renombró Turrican III. Irónicamente, el port de Amiga se publicó antes que el original en la consola de Sega.

Al ser el mismo juego, y haberlo jugado uno atrás del otro, no pude evitar escribir en gran parte una comparación de las dos versiones.

Sonic y Mario congelados en carbonita en Mega Turrican - gráficos que tuvieron que quitar del original y volvieron para el Director's Cut

Sonic y Mario congelados en carbonita en Mega Turrican – gráficos que tuvieron que quitar del original y volvieron para el Director’s Cut

La tercera entrega de la saga construye sobre todo lo que vino antes, con mejoras gráficas en animación, enemigos y escenarios. Continua con la diversidad de escenas y exploración, aunque no incluye de nuevo un nivel shoot ‘em up en la nave de Turrican como en Turrican II. Pero sí explora niveles bajo el agua, por el cielo e incluso sobre un tren en movimiento. Como siempre, el mapa ayuda mucho a la hora de explorar y encontrar secretos. Hablando de secretos, encontré una imagen de No Data!

Se agregan más armas, powerups y enemigos. Tenemos disponilbes las mismas armas que en los juegos anteriores, pero tengo idea que en éste nos dan por primera vez el láser. Es un ítem verde (en la versión de Mega Drive) y el más poderoso, lo que tiene sentido porque es centralizado en un sólo rayo, a diferencia del que rebota y el disparo múltiple repartido. Aunqe para llamarse “laser”, parecen más ráfagas de fuego verde.

Una característica en la que se innovó fue la cuerda de plasma, una cuerda que podemos disparar en cualquier dirección y se engancha a superficies. Esto nos permite alcanzar lugares inalcanzables de otra manera, permitiéndonos columpiarnos para saltar con inercia o subir por los bordes de plataformas. Hay dos powerups nuevos también: un misil teledirigido que se dispara automáticamente junto al arma principal y persigue enemigos. Y un escudo de fuerza que nos hace invulnerables por un tiempo limitado.

Los gráficos de la versión Amiga se ven un poco mejor en comparación a Turrican y Turrican II, y la animación cuando muere Turrican es muy buena. Pero se nota bastante diferencia entre la capacidad gráfica de Amiga y Mega Drive. Amiga tiene una cantidad más limitada de colores. Antes de haber jugado la versión de Genesis, en una de las pantallas de Turrican III me comenté “acá se quedaron sin colores para el escenario”. Las imágenes capturadas de la versión de Amiga se ven un poco menos fieles en este post, porque estaba usando un filtro CRT incluido, pero se nota igual lo que comento de los detalles gráficos.

En Mega Turrican a la derecha se nota mucho más detalle en el parallax de fondo y colores más vívidos.

En Mega Turrican a la derecha se nota mucho más detalle en el parallax de fondo y colores más vívidos.

Mega Turrican a la derecha cuenta con más colores, animaciones en el fondo de pantalla, y transparencia detrás de la cantidad de vidas, tiempo y puntaje en comparación con Turrican III a la izquierda.

Mega Turrican a la derecha cuenta con más colores, animaciones en el fondo de pantalla, y transparencia detrás de la cantidad de vidas, tiempo y puntaje en comparación con Turrican III a la izquierda.

El juego es tan entretenido como los anteriores. Se presta a la exploración para descubrir más vidas, cristales y power ups. Pero tengo que admitir que hubo un nivel que me aburrió. El penúltimo mundo está inspirado en Alien (la película), algo que ya estaba presente en títulos anteriores. Llegué a aburrirme bastante en la versión de Amiga, aunque estaba intentando descubrir todos los secretos de cada nivel. De todas formas se volvió bastante monótono y para cuando lo jugué en versión Mega Drive, intenté encontrar la salida lo antes posible, sin explorar mucho.

Turrican III / Mega Turrican

Algo que me resultó muy interesante fue la música. Ya comenté en los posts anteriores que la música de Chris Huelsbeck es impresionante. Pero en este caso al jugar básicamente el mismo título en plataformas diferentes, noté la diferencia casi de inmediato. Cuando empecé el primer nivel en Mega Turrican, la música tan característica (porque es el primer tema también del primer nivel de Super Turrican), sonaba distinta, no quiero decir peor, pero quiero decir peor…

Por suerte, la antología incluye la opción de escuchar la música de cada juego, versión estudio y versión original. Así que pude compararlas una atrás de la otra, y sí, en mi opinión la versión de Amiga suena mejor que la de Mega Drive. También hay que tener en cuenta que éste era el tercer título de Turrican en Amiga para Chris Huelsbeck, además de haber hecho el tema del título de la versión de R-Type para Amiga de Factor 5. Así que tenía toda la experiencia como para hacer sonar la Amiga de la mejor forma posible.

Turrican Jukebox

Parece que el chip de sonido de Amiga era bastante bueno para su época. Y la versión de Sega no es mala, pero distinta. Salí a buscar por internet, y las comparaciones de Amiga con Mega Drive y Super Nintendo abundan, e incluso hay muchísimos videos comparando versiones de 16 bits de consola contra Amiga. Cómo me perdí toda esta movida al no tener ni idea que existía Amiga durante las Guerras de las Consolas.

Mega Turrican y Super Turrican son los únicos dos juegos que tenía en formato físico antes de adquirir la antología para Nintendo Switch. Y nunca se me ocurrió jugarlos uno atrás del otro para hacer una comparación. Pero tras haber jugado Mega Turrican entero en esta seguidilla de Turricans, me parece que me decido por Super Turrican. Esto basado en mi recuerdo del juego, y puede llegar a cambiar cuando lo vuelva a jugar ahora que estoy repasando todos los títulos de la saga. Pero creo que es otra de las tantas competencias donde Nintendo le ganó a Sega (en mi humilde opinión).

¿Dejé lo mejor para el final? Dejé lo mejor para el final. Los próximos dos títulos van a ser Super Turrican, un juego que jugué cientos de veces pero ahora tengo la versión “Director’s Cut” para probar una habilidad nueva y un nivel entero que quedó afuera. Y después Super Turrican 2, juego que nunca jugué y el último en la saga (por lo menos hasta ahora). Posiblemente juegue alguna otra cosa en el medio, como para sacarme un poco de Turrican. Pero me tiene entusiasmado llegar a jugar éstos últimos dos, y más después de haber pasado por todos los títulos que los precedieron.

Mega Turrican - The End!?

Más Turrican:

El post Turrican III (Amiga) y Mega Turrican (Sega Genesis/Mega Drive) fue publicado originalmente en Picando Código.

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

proyectos Ágiles

Master en Agile – MMA 2024-2025

septiembre 04, 2024 05:12

En octubre de 2024 se iniciará el Barcelona la 14ª edición del Postgrado en Métodos Ágiles (PMA) y otra del Máster en Transformación Agile (MMA) en La Salle (Universitat Ramon Llull), el primero a nivel mundial sobre Agile.

Con el Máster en Métodos Ágiles de La Salle-URL aprenderás a liderar el cambio hacia la Business Agility y a lanzar con éxito iniciativas en entornos complejos y altamente competitivos, reduciendo el Time To Market a fin de maximizar el valor aportado al negocio.

Desarrollarás una manera de pensar transversal e integradora para crear equipos de alto rendimiento mediante Scrum, Kanban, Lean Startup, OKR, diseño organizativo y liderazgo sistémico para elaborar estrategias de escalado Agile en la organización y transformar su cultura, de modo que también aumente la motivación de sus miembros.

Con profesores de primer nivel y visitas a empresas podrás iniciar un cambio hacia la agilidad y resiliencia empresarial en tiempos de incertidumbre.

Esta es una oportunidad única para aprender de profesionales-profesores de primer nivel, con muchos años de experiencia específica en Agile, aplicando principios y métodos ágiles en contextos diversos, especializándose en aspectos concretos,  investigando sobre nuevas técnicas, ponentes en conferencias nacionales e incluso internacionales, que incluso han inventado métodos y escrito libros.

Además, aprenderás a aplicar herramientas de inteligencia artificial para afrontar retos como abordar situaciones complejas, analizar grandes volúmenes de datos, crear agendas para workshops operativos y transformadores, o preparar product backlogs.

El MMA incluye las siguientes certificaciones oficiales:

  • «Certified Scrum Master» (CSM) de la Scrum Alliance, la entidad de certificación Agile de mayor prestigio a nivel internacional.
SAI_BadgeSizes_DigitalBadging_CSM
  • Certified Agile Skills – Scaling 1 de la Scrum Alliance, , la entidad de certificación Agile de mayor prestigio a nivel internacional.
  • Certified Leader de Agile Humans.

Adicionalmente, se incluye la visita a empresas singulares en aspectos concretos:

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

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

PMA – Postgrado en métodos Ágiles

El PMA incluye las siguientes certificaciones oficiales:

  • «Certified Scrum Master» (CSM) de la Scrum Alliance.
  • Opción de acceder al Certified Project, Portfolio, And Operations Management for Business Agility de Businessmap.
AsignaturasTemasProfesores
Fundamentos & InceptionEquipos y Proyectos en entornos complejos.


Principios y métodos más conocidos (Scrum, Lean, Kanban y XP). Facilitadores e impedimentos.

Lanzamiento de Agile en un equipo.


Inception y conceptualización ágil de proyecto, priorización ágil, historias de usuario,  elaboración de Product Backlog, técnicas de priorización.

Xavier Albaladejo


Silvia Sistaré

Agustín Yagüe

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

 

Teodora Bozheva

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

 

Visual thinking.

Steven Wallace

 

Silvia Sistaré

Virginia Armas

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

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

Customer development – Lanzando y escalando startups ágiles, las tres fases de un producto.

Lean Startup – Desarrollo de producto basado en prototipos y experimentos. Bancos de ideas, desarrollo basado en hipótesis.

Juncal Guinea


Lucía Barroso
Ingeniería ágil User eXperience y prototipado en Agile.

 

ALM ágil, eXtreme Programing, Software Craftsmanship, testing ágil.

BDD y TDD. Desarrollo guiado por pruebas (de aceptación y unitarias).

Métricas Accelerate y SW Delivery assessment.

Cómo trabajar con código heredado y reducir la deuda técnica.

DevOps
Juncal Guinea

 

Cristina Verdi
Trabajo Final de PostgradoDurante el Postgrado se realiza un caso práctico de introducción de los contenidos en un equipo ágil en una empresa real. Para ellos los alumnos se organizan en equipos multidisciplinares utilizando Scrum, con feedback regular de un tutor con experiencia en transformación de equipos. 

El Postgrado tendrá una duración de 4 meses y se realizará viernes tarde y sábado por la mañana.

Ver también:

MMA – Master en Métodos Ágiles

Incluye todas las asignaturas del Postgrado (PMA) y, adicionalmente, las siguientes asignaturas especializadas en Business Agility, agilidad organizacional y transformación (aparte de las tres certificaciones indicadas al inicio y las visitas a empresas):

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

 

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


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

 

Business Agility con ViMa – agilidad para equipos de negocio

Agile-Lean Management

Teodora Bozheva

  Xavier Quesada


Xavier Albaladejo

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

 

Tipos de cultura empresarial, transformación cultural.

Joserra Díaz

 

Jasmina Nikolic
Jaume Gurt

Transformación ContinuaEstrategia de despliegue de Agile en organizaciones, gestión del cambio, estructuras ágiles, cómo vender Agile a la Dirección. Contratos ágiles.

Enterprise continuous improvement.

Xavier Albaladejo

 

Ángel Medinilla
Scaling Agile Escalado (LESS, Spotify, Nexus, SAFe, Unfix), desescalado y auto-organización empresarial (reinventing organizations, sociocracy 3.0, liberating structures, …), equipos distribuidos.

 

Impact Mapping, Product Portfolio Management, Roadmapping, Budgeting for Agile

Adrian Perreau
Fernando Palomo

 

Mattijas Larsson

Trabajo Final de MásterDurante el Máster se realiza un caso práctico de introducción y aplicación de Agile en una empresa real, incluyendo la parte de transformación organizativa, de métodos y de cultura. Para ellos los alumnos se organizarán en equipos multidisciplinares utilizando Scrum, con feedback regular de un tutor con experiencia en transformación organizativa.Xènia Castelltort (oratoria / public speaking para poder explicar tus ideas de manera convincente)

El Máster tendrá una duración de 8 meses y se realizará viernes tarde y sábado por la mañana (incluye los estudios indicados en el Postgrado).

El cambio en la organización comienza por el propio cambio, para también poder dar ejemplo. Por ello en el MMA se realizan diferentes ejercicios de auto-conocimiento:

  • Cómo el alumno trabaja en equipo.
  • Estilo de liderazgo del alumno (según el paradigma Agile).

Como en las últimas ediciones, contaremos con la participación de empresas que nos explicarán sus experiencias de transformación y donde trabajan con modelos de gestión desescalados (basados en Sociocracia, NER y otras alternativas).

Información adicional

  • Perfil de los estudiantes: 30-45 años (no son recién licenciados, son personas con experiencia profesional).
  • Alrededor del 50% son mujeres.
  • 15% de los estudiantes ya no son del ámbito tecnológico, son pioneros-innovadores en otras industrias.
  • Alumnos de diferentes disciplinas – Product Owners, Scrum Masters, Agile Coaches, líderes de equipos, Project Managers, managers funcionales, ingenieros SW. Van a adquirir conocimientos de Agile “on-top” de todo eso (y a aprender unos de otros).
  • Lo que les caracteriza: todos son agentes de cambio en su contexto (equipo, área, empresa).
  • Sus 20 profesores (de reconocimiento internacional) son el MAYOR VALOR DIFERENCIAL del PMA y del MMA.

Testimoniales

Me ha permitido tener conocimientos sobre varios temas súper importantes dentro de la Transformación Digital. Me dio herramientas para crecer a Agile Coach y, además, para tener mejores conversaciones y discusiones con las empresas en donde he trabajado

Carolina Graffe

Estoy desplegando el TFM en mi empresa, Además, no estoy sola. Uno de mis compañeros del equipo ha sido contratado como consultor por mi empresa para darnos soporte. Así que no sólo estoy aplicando lo que yo aprendí, sino que el MMA me ha permitido ampliar mi círculo de contactos relevantes, que me permite seguir aprendiendo.

Susana Santillán

Estoy trabajando como agente del cambio y mis aportaciones son muy valoradas por mi jefe y compañeros. Por el feedback recibido, mis aportaciones están muy por encima de lo esperado para mi rol.

Robert Avellaneda

Tengo mucho más contexto y más herramientas para el día a día. Incluso a nivel personal también me está ayudando mucho

María Hachero

Además de los conocimientos concretos que se reciben, uno de los principales cambios que han experimentado los alumnos es mayor perspectiva en los problemas, cómo abordar la complejidad en las empresas, en su trabajo y en las relaciones entre personas y en equipos. Han ganado discurso y aplomo para defender de manera más objetiva propuestas de cambio y mejora.

Encuesta a alumnos de las ediciones anteriores:

(*) Las personas que han valorado el impacto como «neutro o poco» usualmente son perfiles muy especializados en contextos muy estáticos, con lo cual les es difícil cambiar de «profesión» e introducir cambios en sus organizaciones (aunque algunos de ellos incluso dan conferencias sobre cómo van avanzando en esos contextos tan singulares).

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

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

Picando Código

Los secretos de Super Turrican, Mega Turrican y Turrican III

agosto 27, 2024 11:00

En el post de Turrican II me preguntaba sobre el desarrollo de Turrican III (Amiga), Mega Turrican (Genesis/Mega Drive) y Super Turrican (SNES). Resulta que el sitio web de Factor 5 sigue funcionando, con un diseño de hace al menos 10 años, pero funcional y lleno de contenido interesante.

Factor 5

¡Hermoso sitio web! factor5.de

Entre las secciones del sitio, podemos encontrar “Secretos”. Las páginas de Super Turrican, Mega Turrican y Super Turrican 2 fueron actualizadas porque fueron publicados en la Virtual Console de Wii. Además de compartir algunos trucos, cada página da un poco de información del desarrollo y lanzamiento de cada uno. Esto me aclaró bastante cómo se fueron desarrollando. Seguramente todo esto se comenta en el documental que tengo de Turrican, pero lo miré hace mucho tiempo y no había jugado tantos títulos como ahora en ese entonces.

Breve historia de Turrican

El primer Turrican empezó en Commodore 64, una computadora muy popular en la década de 1980. Para cuando el juego estaba 75% terminado en otoño de 1989, se volvió evidente que Commodore 64 estaba empezando a ser eclipsada por las ventas de la nueva computadora Amiga. Así que abandonaron el plan inicial de terminar el título (que en ese momento se llamaba “Hurricane”) para C64 y luego portarlo a Amiga.

El desarrollo se empezó de cero viendo lo que había jugable en la C64, pero tratando al juego como un título de Amiga. Se rediseñó al personaje, se volvieron a desarrollar los controles para aprovechar la Amiga, fue el primer juego en la plataforma en tener movimiento fluido en la pantalla en cualquier dirección. Más importante todavía, Amiga ofrecía el poder en audio para colaborar extensivamente con Chris Hülsbeck, quien había proporcionado el tema principal del port a Amiga de R-Type desarrollado por Factor 5.

Con el éxito del primer título, el plan era un juego más grande, mejor, y con tecnología más avanzada. Para Turrican II, se desarrollaría para Amiga desde el principio, lo que explica eso que comentaba en el post de que se ve y se siente mucho mejor.

Super Turrican

Super Turrican - EnemigosSuper Turrican fue el primer encuentro del equipo con desarrollo para consolas. El proyecto arrancó simultáneamente con Mega Turrican en 1991, pero las herramientas y el hardware de desarrollo interno llevó más tiempo de desarrollo del lado del SNES y demoró el verdadero trabajo de contenido al verano de 1992. Con poco tiempo para completarlo, el juego fue desarrollado durante el otoño e invierno de 1992 en una sesión masiva de 3 meses de noches largas en oficinales temporales en un apartamento tipo loft en Cologne, Alemania.

Mientras los próximos dos Turrican intentaron variar la fórmula un poco, Super Turrican básicamente seguía el espíritu de los primeros dos Turrican para Amiga. Niveles no-lineales con mucha exploración y muchos secretos y bonus escondidos.

Hubo bastante contenido que no llegó a la versión final del juego. En el manual se pueden ver varias criaturas que no se encuentran en la versión oficial debido a limitaciones con la memoria. Se pidió que el juego se entregara en 4 Mbit, el tamaño de cartucho más chico disponible en ese momento, después de que el equipo de desarrollo terminara un título de 6 Mbit.

No sólo tuvieron que cortar partes de arte en varios lugares, sino también un nivel entero y una característica del arma Rayo: No sólo podía congelar enemigos, también podía derretir enemigos congelados, algo que el jugador debía descubrir en el mundo de hielo (¡spoiler!) y eso llevaba a un nivel con el Transporte Robot a toda velocidad por las nubes. Pero no cabía en el cartucho, así que todo ese material quedó olvidado en un diskette hasta que vió la luz Super Turrican – Director’s Cut.

Tengo mucha expectativa de jugar esa versión del director y ver todo ese contenido que nos perdimos originalmente.

Trucos para Super Turrican

En el mismo sitio agregan que aprovechando la re-edición para Virtual Console, abrieron sus viejas herramientas de edición y prepararon mapas para cada nivel de Super Turrican. De esta forma es más fácil encontrar cada diamante y vida extra escondida a lo largo del juego. También hay algunos trucos de vidas y demás, y el menú de sonido para poder escuchar la música de Chris Hülsbeck:

Saltar nivel: R – L – ↓ – R – A
Modo invencible: L – L – L – R – R – R – L – L – L
Menu de sonido: Ir a las opciones, Salir, mantener apretado L, R, X, A y presionar Start.
Ver el final: R – L – ↓ – R – B

Mapas Super Turrican

Mega Turrican

Mega Turrican - EnemigosMega Turrican tiene una historia compleja, enfatizado en el hecho de que se terminó de desarrollar en la primavera de 1993, poco después de Super Turrican, pero no fue publicado hasta 1994. Mega Turrican empezó en el otoño de 1991 como Turrican III en Amiga, pero no se completó más que un prototipo con la “plasma rope” nueva y algunos gráficos del primer mundo antes de migrarlo a Genesis/Mega Drive.

Gracias a los esfuerzos en hardware de un amigo del equipo que trabajaba en el Servicio Secreto Alemán, crearon sus propios kits de desarrollo y ambientes de software para el Super Nintendo y Genesis/Mega Drive, los cuales alcanzaron operación completa a principios de 1992. Posteriormente, el enfoque de la compañía Factor 5 cambió hacia el desarrollo de consolas, con Mega Turrican encabezando el esfuerzo en el frente Sega. El último encuentro con Amiga eventualmente se volvió Turrican 3, el cual fue un port de Mega Turrican que irónicamente se publicó antes que el original.

Mega Turrican intentó innovar en la franquicia. Uno de los aspectos fue encontrar un equilibrio entre el estilo de exploración de títulos anteriores y el enfoque más lineal que encarnaba el diseño de juegos de acción Japonés. El otro fue la cuerda de plasma, un dispositivo sumamente flexible para engancharse basado en física. Esto agrega nuevas formas de explorar los niveles una vez dominada la curva de aprendizaje para dominar esta nueva herramienta.

Chris Hüelsbeck vuelve para crear la espectacular banda sonora, inspirado en el peculiar hardware de sonido del Genesis/Mega Drive. Este es también el primer título en intentar jefes más elaborados y complicados.

Trucos para Mega Turrican

Saltar: → – ← – ↓ – → – B
Energía infinita: A – A – A – B – B – B – A – A – A
Re-play: Right – ← – ↓ – → – A
Modo Reverso: ↑ – ↑ -↓ – ↓ – ← – → – ← – → – A – B

Mapas Mega Turrican

Conclusión

Toda esta situación me hizo dudar qué título debería jugar siguente. Cronológicamente debería ser “Turrican III”, “Super Turrican” y “Mega Turrican”. Pero Turrican III es un port para amiga de Mega Turrican, ¿así que de repente debería jugar uno sólo de estos dos? Pero también sería interesante jugar ambas versiones para poder comparar las diferencias en las plataformas. Me parece que voy a hacer: Turrican III, Mega Turrican y después Super Turrican: Director’s Cut.

Qué bueno que todavía existan páginas como la de Factor 5. Esto de republicar los trucos en el blog me da nostalgia de mis primeros sitios web allá por fines de los 90’s. Uno de mis tantos sitios en ese momento tenía una sección de trucos para juegos de Nintendo. ¡Publicado en Geocities!

Más Turrican:

El post Los secretos de Super Turrican, Mega Turrican y Turrican III fue publicado originalmente en Picando Código.

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

Blog Bitix

Desempaquetado del ratón inalámbrico Logitech Signature M750

julio 23, 2024 09:00

Tras probar un ratón inalámbrico de los baratos pasado un tiempo me quedé con muy malas impresiones por la perdida de conectividad principalmente que era muy molesta. Pasé a un ratón con cable más fiable y tras 5 años el botón derecho me ha empezado a fallar y reconocer el clic aleatoriamente. Tras estar usando un Apple Magic Mouse que generalmente me ha funcionado bien en cuanto a conectividad he vuelto a darle una nueva oportunidad a un ratón inalámbrico pero ya de más calidad, finalmente he elegido el Logitech Signature M750. En el artículo hago un análisis del ratón y mis primeras impresiones.

Continuar leyendo en Blog Bitix

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

Header Files

La trampa al usar semántica de movimiento con std::string

julio 16, 2024 10:00

La trampa al usar semántica de movimiento con std::string

La semántica de movimiento de std::string puede ser complicada y, a menos que tengamos información previa sobre los tamaños esperados de las cadenas, puede tener el efecto contrario y hacer que el código sea más lento. La razón detrás de esto es la optimización de cadenas pequeñas (SSO, por sus siglas en inglés). que consiste, en resumidas cuentas, en tratar al objeto como si fuera una unión, de forma que si la cadena es más corta que un tamaño dado, se almacena en el mismo bloque de memoria del objeto en lugar de asignar memoria dinámica. Cuando la cadena supera ese tamaño, la cadena se almacena en un bloque diferente.

¿Qué es la Optimización de Cadenas Pequeñas (SSO)?

La SSO es una técnica utilizada en la implementación de std::string para optimizar el uso de memoria y el rendimiento. En lugar de asignar memoria dinámica para todas las cadenas, la SSO almacena cadenas pequeñas directamente en el objeto std::string (como si de una unión se tratase). Se puede ver la SSO en acción en este ejemplo.

Esta técnica evita la sobrecarga de la asignación de memoria dinámica, que puede ser costosa en términos de tiempo y recursos. Sin embargo, esta optimización introduce algunas consideraciones importantes al mover objetos std::string.

Nota: La SSO no es parte del estándar de C++ sino más bien una optimización de algunos compiladores. Igualmente, el tamaño máximo para considerar una cadena como pequeña no tiene que ser el mismo en todas las implementaciones ni plataformas.

El constructor de movimiento de std::string

Al mover cualquier objeto en C++, estamos dando la posibilida de realizar una copia optimizada. La eficiencia aumenta cuando tenemos recursos externos que podemos intercambiar, como un puntero a un bloque de memoria o un handle de fichero. Sin embargo, para el resto de datos, aún tenemos que copiar datos. Si la cadena es pequeña y la SSO está en acción, no hay ningún puntero que intercambiar y todavía estamos copiando los datos base de std::string.

De hecho, al mover, tenemos que garantizar que el objeto original se mantenga en un estado válido, lo cual normalmente se hace estableciendo algunos valores por defecto. En la práctica, esto significa que estamos copiando una vez y asignando una vez, duplicando la cantidad de operaciones en comparación con una copia normal. Por lo tanto, si nuestras cadenas se espera que siempre (o la mayoría del tiempo) sean más cortas que el límite de SSO, entonces un movimiento perjudicaría el rendimiento.

Comparación de Copia vs Movimiento

Para ilustrar mejor este punto, se puede comparar el rendimiento de la copia y el movimiento para cadenas pequeñas, grandes y una mezcla de ambas. El siguiente ejemplo permite visualizar las diferencias entre ellas. En este benchmark, se estableció un tamaño de 32 caracteres para tener aproximadamente un 50% de cadenas pequeñas y un 50% de cadenas grandes. Los resultados muestran cómo el movimiento de cadenas pequeñas puede ser menos eficiente que una simple copia debido a la SSO.

Benchmark std::string

Conclusión

En resumen, la semántica de movimiento de std::string no siempre es la mejor opción, especialmente cuando se trata de cadenas cortas que se benefician de la SSO. Es crucial considerar el tamaño esperado de las cadenas al decidir entre copiar o mover std::string. Esta decisión puede tener un impacto significativo en el rendimiento de nuestra aplicación.

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

info.xailer.com

Protegido: La cocina de Xailer

julio 02, 2024 03:15

Este contenido está protegido por contraseña. Para verlo, por favor, introduce tu contraseña a continuación:

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

info.xailer.com

Plugin de despliegue de archivos

junio 11, 2024 11:35

Os presento un nuevo plugin que puede ser muy útil para todos aquellos que os dedicáis a generar ejecutables tipo CGI que luego subís a un servidor web o cualquier otro tipo de archivo que querías desplegar un vuestros servidores de forma rápida.

Su funcionamiento es muy sencillo: el plugin detecta cuando se realiza una compilación y enlazado correcto de un archivo CGI y lo sube a Internet utilizando los servicios de CURL. En Xailer 9 existe una carpeta especial para los proyectos tipo Web de nombre ‘www’. Cuando el plugin detecta que se ha realizado un salvado de algún archivo en esa carpeta, hace automáticamente el despliegue.

Es más que probable que no queramos que esté realizando el despliegue constantemente, por lo que se ha incluido una opción de menú para activarlo o desactivarlo.

Este plugin es capar de realizar un despliegue múltiple si detecta que estamos utilizando WSL para la generación de los archivos CGI para el entorno Linux (nueva función de Xailer 9). En dicho caso no sólo despliega en nuestro servidor en Internet, sino que también despliega en WSL

Este sería un ejemplo de despliegue:

Su configuración es bastante sencilla. Tan sólo hay que indicar las direcciones URL donde queremos que despliegue y nuestras credenciales.

Estas son la propiedades que hay que configurar y viendo su nombre espero que se auto-expliquen, así mismas:

  • URL donde se despliegan los archivos tipo CGI
  • URL donde se despliegan el resto de archivos
  • Path donde se copian el resto de archivos en entornos WSL
  • Extensión de archivos CGI que se reconocen
  • Directorio donde se ubicarán los archivos JavaScript
  • Directorio donde se ubicarán los archivos CSS
  • Directorio donde se ubicarán el resto de archivos
  • Nombre de usuario de la conexión FTP
  • Contraseña de la conexión FTP

El plugin es susceptible de importantes mejoras. Como por ejemplo, poder establecer distintas URL y credenciales dependiendo del proyecto. Hemos decidido no incluir esa funcionalidad porque cada usuario tendrá su propia preferencia. No obstante, si alguien se anima a hacerlo, encantado de echarle una mano para cualquier duda que pueda tener.

Os adelanto que sólo funciona con Xailer 9 ya que se apoya en alguna función que no existe más que en Xailer 9.

Podéis descargar el plugin de este enlace.

Un saludo y hasta pronto

Ignacio Ortiz de Zúñiga
[Equipo de Xailer]

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

Juanjo Navarro

Nueva edición del Technology Radar (la 30)

mayo 21, 2024 06:31

Si no conoces el Technology Radar de la empresa Thoughtworks, deberías echarle un vistazo.

Se trata de un informe semestral donde se analizan una serie de puntos (“blips” los llaman) sobre el mundo del desarrollo de proyectos tecnológicos.

Estos blips se dividen en cuatro tipos:

  • Técnicas
  • Herramientas
  • Plataformas
  • Lenguajes & Frameworks

Para cada blip te aconsejan:

  • Adoptar
  • Probar
  • Evaluar – mantenerse al tanto y jugar un poco con él para conocerlo.
  • Resistir – mejor no usarlo, es dudoso su futuro o utilidad.

Esta última edición (la 30) está llena de IA y devops, cómo no. Yo me suelo fijar en temas prácticos (en Herramientas o en Lenguajes y Frameworks, sobre todo).

Aquí os dejo lo que más me ha llamado la atención (y he probado más o menos) de la última edición:

  • Pop – Herramienta para compartir la pantalla para hacer Pair Programming.
  • Aider – Una IA que hace de “coworker” de programación y me ha parecido muy bien pensado.
  • Continue – Un “Github Copilot” opensource en el que puedes elegir qué LLM utilizar (con el consiguiente coste por el uso del API si es de pago, claro). Puedes también utilizar un LLM local corriendo en tu infraestructura.
  • Dify – Un creador “gráfico” de aplicaciones “LLM” bastante impresionante. Permite diseñar un “flujo” de trabajo, donde vas haciendo consultas a distintos modelos IA, unir la información, hacer otras llamadas dependiendo de la respuesta anterior, etc. Además tiene integrado un sistema RAG con lo que le puedes subir documentos que la IA utilizará como referencia.
  • Crabviz – Utilidad para VSCode que genera un gráfico de llamadas entre clases.
  • Electric – Librería y framework que permite crear aplicaciones móviles o webapps con una base de datos “local” (que se ejecuta en el propio móvil o la página) y que automáticamente se sincroniza con un PostgreSQL en el back.
  • LiteLLM – Algo así como un “proxy” LLM. Permite configurar distintos LLM y acceder a ellos con un API común.

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

Una sinfonía en C#

Configurar Docker + HTTPS + nginx

mayo 21, 2024 12:00

“Introducción”

Cuando queremos probar algo en local (una aplicación web), dentro de un contenedor, no podemos utilizar https como desde Visual Studio o IIS. Si necesitamos sí o sí https, debemos configurar algunas cosas, como por ejemplo, un certificado autofirmado, nginx, etc. En este post vamos a detaler cómo hacerlo.

Pasos

Vamos a necesitar hacer un par de cosas, voy a detallar los pasos a seguir en una PC con Windows y una aplicación .NET Core, es que lo que yo uso.

Básicamente pondremos nuestra aplicación en un contenedor, configuraremos nginx para que haga de proxy y que además tenga https. Luego un docker compose que levante todo.

Crear certificado autofirmado

Para crear certificados autofirmados, podemos utilizar openssl. En Windows, podemos instalarlo desde aquí.

y ejecutar este comando:

localhost.conf

[req]
default_bits       = 2048
default_keyfile    = localhost.key
distinguished_name = req_distinguished_name
req_extensions     = req_ext
x509_extensions    = v3_ca

[req_distinguished_name]
countryName                 = Country Name (2 letter code)
countryName_default         = US
stateOrProvinceName         = State or Province Name (full name)
stateOrProvinceName_default = Texas
localityName                = Locality Name (eg, city)
localityName_default        = Dallas
organizationName            = Organization Name (eg, company)
organizationName_default    = localhost
organizationalUnitName      = organizationalunit
organizationalUnitName_default = Development
commonName                  = Common Name (e.g. server FQDN or YOUR name)
commonName_default          = localhost
commonName_max              = 64

[req_ext]
subjectAltName = @alt_names

[v3_ca]
subjectAltName = @alt_names

[alt_names]
DNS.1   = localhost
DNS.2   = 127.0.0.1
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -config localhost.conf -passin pass:12345678

Esto creará dos archivos, localhost.crt y localhost.key, estos archivos los usuaremos en nginx.

Ahora necesitamos registrar el certificado como confiable ya que es auto-firmado. (es decir, registrar en Windows como confiable)

En el Administrador de Certificados (certmgr.msc), puedes encontrar esta ubicación siguiendo estos pasos:

Abrimos el Administrador de Certificados.

  • Para esto escribimos certmgr.msc en el diálogo Ejecutar (Win + R).
  • En el Administrador de Certificados, expande el árbol de Certificados “Usuario Actual” en el panel izquierdo.
  • Debajo de esto, expande la carpeta Autoridades de Certificación Raíz Confiables.

Hacemos clic en la carpeta Certificados bajo Autoridades de Certificación Raíz Confiables.

Esta es la ubicación equivalente a Cert:\CurrentUser\Root en PowerShell.

Luego

En el Administrador de Certificados (certlm.msc, Certificate Manager for local machine), puedes encontrar esta ubicación siguiendo estos pasos:

  • Abre el Administrador de Certificados para la Máquina Local. Puedes hacer esto escribiendo certlm.msc en el diálogo Ejecutar (Win + R).
  • En el Administrador de Certificados, expande el árbol Certificados (Computadora Local) en el panel izquierdo.
  • Debajo de esto, expande la carpeta Personal.
  • Haz clic en la carpeta Certificados bajo Personal.

Ahora nginx usará los archivos de certificado y clave para servir https. Y deberías estar bien.

Configurar nginx

Para esto simplemente vamos a crear un archivo de configuración para nginx, que será el siguiente:

nginx.conf

worker_processes 1;

events { worker_connections 1024; }

http {

    sendfile on;

    upstream web-api {
        server api:80;
    }

    server {
        listen 80;
        server_name localhost;

        location / {
            return 301 https://$host$request_uri;
        }
    }

    server {
        listen 443 ssl;
        server_name localhost;

        ssl_certificate /etc/ssl/certs/localhost.crt;
        ssl_certificate_key /etc/ssl/private/localhost.key;

        location / {
            proxy_pass         http://web-api;
            proxy_redirect     off;
            proxy_http_version 1.1;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection keep-alive;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;
            proxy_set_header   X-Forwarded-Host $server_name;
        }
    }
}

Le decimos a nginx que utilice el certificado y la clave que creamos antes, y que escuche en el puerto 443. y con el proxy_pass le decimos que redirija las peticiones al servicio que escucha en el puerto 80. (más adelante ese será el nombre del servicio en el docker compose)

Ahora creamos el Dockerfile para nginx:

FROM nginx:alpine

COPY ./nginx.conf /etc/nginx/nginx.conf
COPY localhost.crt /etc/ssl/certs/localhost.crt
COPY localhost.key /etc/ssl/private/localhost.key

CMD ["nginx", "-g", "daemon off;"]

Básicamente copiamos el archivo de configuración y los archivos de certificado y clave al contenedor.

Configurar nuestra app

En este caso una simple aplicación .NET Core, que escucha en el puerto 80.

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app

COPY *.csproj ./
RUN dotnet restore

COPY . ./
RUN dotnet publish -c Release -o out

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app

ENV ASPNETCORE_HTTP_PORTS 80

EXPOSE 80
EXPOSE 443

COPY --from=build /app/out ./

CMD ["dotnet", "app.dll"]

Docker compose

version: "3.7"

services:

reverseproxy:
    build:
      context: ./nginx
      dockerfile: Dockerfile.nginx
    ports:
      - "8080:80"
      - "1443:443"
    restart: always

api:
    depends_on:
      - reverseproxy
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8088:80"
    restart: always

Simplemente apuntamos los dos servicios a sus Dockerfiles, y abrimos el puerto 1443 para https.

Si vemos algún error en el navegador relacionado con https lo más probable es que no hayamos registrado el certificado como confiable.

Dejo por acá un repositorio con el código

Nos leemos.

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

Arragonán

El lado estratégico de Domain-Driven Design. CommitConf 2024

mayo 08, 2024 12:00

Hace unas semanas estuve en Commit Conf en Madrid, evento al que no iba desde hace mucho. Estuve compartiendo la charla El lado estratégico de Domain-Driven Design, iterando ligeramente la que hice hace unos meses en La Vertical, a su vez basada en una charla más larga (y espesa) que he impartido in-company en varias ocasiones.

Foto de la sala de conferencias del track 1 del evento

En los últimos años ha crecido el interés y la adopción de Domain-Driven Design en la comunidad de desarrollo de software. Ahora es bastante habitual oír hablar del lado táctico de DDD, la mayoría de las veces acompañado del uso de ports & adapters (aka Hexagonal Architecture). Pero, al menos en castellano, no he visto hablar apenas de DDD estratégico y lo que nos puede aportar a nivel de Sociotechnical Architecture.

Así que de ahí vino buena parte de mi motivación de proponer repetirla en un evento mucho más masivo como es la Commit Conf.

La presentación está dividida en 4 bloques:

  • Introducción a DDD y específicamente a la parte estratégica
  • Resumen de las actividades estratégicas basado en el Domain-Driven Design Starter Modelling Process de DDD Crew
  • Un ejemplo práctico de DDD estratégico basado en un caso real, mostrando su división y conexión entre dominios visibilizándolo con un Context Map un tanto enriquecido con su clasificación desde diferentes puntos de vista
  • Otras consideraciones a tener a nivel de la organización de equipos

Aquí os dejo el vídeo de la charla

Y el genially que usé para la presentación

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

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

CAS2017: Conferencias Agile-Spain

abril 11, 2024 08:24

La CAS2017 ha sucedido hace un par de días, y empiezo a leer las primeras impresiones, felicitaciones, quejas, enhorabuenas y protestas... Mi visión sobre la CAS2017 &nbsp;¿Qué ha sucedido este año? Desde mi punto de vista personal, no puedo dar muchos detalles del contenido. ¡He visto muy pocas charlas! :) La CAS tiene cada vez para mi más de punto de encuentro que de conferencia dónde

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

Arragonán

Reduciendo riesgos con tests de carga

abril 04, 2024 12:00

Hace varias semanas estuve involucrado en realizar algunos tests de carga en Genially, algo que no había tenido necesidad de hacer desde que trabajé en Inditex lanzando un nuevo servicio interno.

Esto venía dado por unos cambios en los que estuvimos trabajando un par de equipos para mejorar la experiencia de uso de una parte del producto, lo cual implicó un cambio bastante importante a nivel de arquitectura.

Con estos cambios teníamos 2 riesgos:

  • Que aunque la experiencia de uso de la funcionalidad mejorase esto pudiera impactar negativamente en un funnel de conversión.
  • Que la nueva solución que habíamos implementado pudiera causar problemas dependiendo de la carga y tuviéramos incidencias.

El primer riesgo lo minimizamos realizando un rollout incremental, que es como lanzamos la mayoría de cambios relevantes en Genially. Esto, en este caso, significó lanzar los cambios internamente bajo una feature flag para obtener feedback cualitativo y luego abrirlo a un porcentaje del tráfico para observar las métricas de producto.

El segundo riesgo, como mencionaba al principio, lo minimizamos realizando algunos tests de carga.

¿Pero qué es un test de carga?

Es un tipo de prueba en la que se genera tráfico de forma artificial para evaluar la respuesta o capacidad de un sistema ante una carga determinada de trabajo o de personas usuarias, por lo que puede servir para comprobar tanto el rendimiento como el escalado de un sistema.

Para esto, antes de ejecutar la prueba, necesitamos tener definido previamente qué y cómo lo vamos a observar para poder consultarlo tras su ejecución (tiempos de respuesta, consumo de recursos, etc). Así que el entorno sobre el que vayamos a probar tiene que ser observable; en este caso, lo que más nos va a interesar son las métricas y, en caso de que empiece a degradarse el servicio, también las trazas pueden ayudar a identificar el origen del problema con mayor facilidad.

En ocasiones, este tipo de pruebas se tienden a hacer con personas reales de manera algo informal, en plan “entrad aquí X personas a hacer Y metiéndole caña y vamos a ver cómo van las métricas Z”. Eso puede ser perfectamente válido para tener una idea general de cómo responde el sistema con una carga un tanto aleatoria, pero tiene el problema de que no es repetible ni controlado, por lo que de ese modo no podemos dar seguimiento a los resultados obtenidos de forma consistente.

Para tener consistencia en este tipo de pruebas, hay herramientas que nos permiten automatizarlas, de ese modo obtenemos escenarios controlados y repetibles a los que sí podemos dar seguimiento. Con estas herramientas, podremos definir distintos escenarios en los que queremos probar el sistema y observar si se mejora o empeora comparando los resultados de antes y después de un cambio.

En cuanto a herramientas concretas, en el pasado usé Apache HTTP Server Benchmarking Tool y JMeter, pero en la última ocasión lo hice con k6 por recomendación de mi compañero Manu Franco. La verdad es que me pareció una herramienta fácil de empezar a usar, y viendo su documentación también muy potente, así que de momento se ha convertido en mi preferencia.

Tipos de tests de carga

Dentro de los tests de carga, se pueden clasificar en subtipologías dependiendo del objetivo de la prueba y del patrón de generación de tráfico utilizado. Me gusta mucho la gráfica y la explicación de la propia documentación de k6.

Esquema representando los distintos tipos de tests

  • Smoke tests: son pruebas sobre el sistema de corta duración (segundos o pocos minutos) con una carga baja, con el objetivo de comprobar que todo funciona razonablemente bien sin consumir muchos recursos. De primeras, no los hubiera incluido como test de carga, pero dada la aproximación de esta herramienta de generar tráfico concurrente, les compro el incluirlo. En este caso, se podrían lanzar de forma bastante recurrente para detectar errores de configuración a nivel de aplicación o anomalías en las métricas de forma temprana.
  • Average-load test: son pruebas sobre el sistema de duración media (minutos-hora) con una carga similar a la habitual, con el objetivo de asegurar que los cambios introducidos no impactan negativamente en el contexto habitual del sistema. Esto podría hacerse de forma periódica para encontrar potenciales problemas que se hayan podido introducir.
  • Stress test: son pruebas sobre el sistema de duración media (minutos-hora) con una carga por encima de la habitual, con el objetivo de comprobar el comportamiento del sistema con un tráfico bastante superior al habitual. Esto nos puede ser útil, por ejemplo, para prepararnos para campañas como navidad o rebajas en el mundo del comercio electrónico.
  • Spike test: de duración corta (unos pocos minutos) con una carga que sobrepase mucho la habitual del sistema. Su objetivo es ver cómo se comporta con un pico de tráfico masivo durante un tiempo más limitado. Escenarios para los que esto puede ser útil pueden ser prepararse para las primeras horas del Black Friday, si se va a lanzar un anuncio en prime time en televisión, etc.
  • Breakpoint test: de duración indeterminada y una carga incremental hasta llegar a que el sistema se rompa o llegue al límite que hayamos definido. En este caso, el objetivo es llevar el sistema al extremo máximo para conocer en qué momento nuestro sistema no da más de sí o hasta dónde permitimos escalarlo si la infraestructura del sistema puede ir hacia “infinito”. Los escenarios podrían ser comprobar optimizaciones de partes del sistema o trabajar en un plan de contingencia si en algún momento el sistema se acerca a su límite.
  • Soak tests: de larga duración (varias horas) y una carga similar a la habitual. Su objetivo es detectar problemas surgidos a partir de un uso extendido del sistema, como el aumento del consumo de infraestructura o la degradación de los tiempos de respuesta. Esto nos puede interesar especialmente cuando no somos los dueños de la infraestructura en la que corre nuestro sistema y queramos comprobar que quienes lo vayan a operar no se encuentren sorpresas posteriormente.

¿Cómo lanzar los tests de carga?

En un mundo ideal lo probaríamos en algún entorno aislado que se asemeje mucho a producción a nivel de infraestructura, pero no siempre podremos contar con esa posibilidad. Y la frencuencia de ejecución dependerá de cada contexto.

Por ejemplo, cuando trabajaba en Inditex, disponíamos de un entorno específico para este tipo de pruebas. Y dado que no era posible realizar llamadas entre entornos distintos debido a que estaba limitado a nivel de red, sabíamos que podíamos probar nuestros servicios de forma aislada sin necesidad de coordinarnos con equipos no involucrados en estas pruebas.

Por otro lado, para llevar a cabo pruebas preliminares del cambio de arquitectura al que me refería en Genially, las estuvimos realizando en un entorno efímero. A nivel de infraestructura, estos entornos efímeros son bastante limitados en comparación con el de producción, pero nos permitía realizar algunas validaciones en un entorno aislado también sin necesidad de coordinación. Utilizamos este entorno para ejecutar una serie de smoke tests y un mini average-load test para obtener las métricas base. Luego introdujimos los cambios relevantes y comprobamos si surgía alguna anomalía para ver si había que iterar algo, una vez visto que no había nada raro podíamos ir a producción con mayor confianza y darle seguimiento al uso real de las primeras horas.

En los casos que describo lanzábamos las pruebas de forma manual y luego analizábamos los resultados. Pero también existen contextos donde estas pruebas se lanzan automáticamente incluso en pipelines de continuous delivery. Así que se puede echar para atrás una release si un test falla dado el límite marcado como aceptable en una métrica. Por ejemplo si dada una carga se supera el máximo de latencia de peticiones, no se consigue ingestar un mínimo de peticiones por segundo, etc.

Concluyendo

Hay lugares donde este tipo de pruebas son muy relevantes por su contexto y forman parte del camino de entrega del software. En mi caso no han formado nunca parte de mi flujo habitual de trabajo, pero han habido ocasiones en las que me han resultado muy útiles para lanzar nuevos servicios, nuevas funcionalidades o para introducir cambios relevantes en la arquitectura con una mayor confianza.

Aunque nunca hay que olvidar que, como cualquier prueba automática, estas pruebas pueden ayudar a minimizar el riesgo pero no garantizan la ausencia total de problemas de degradación o errores. Ya que el tráfico artificial nunca será igual al generado a partir del comportamiento real de las personas que utilizan nuestro software, así que es importante invertir primero en observabilidad y en comprender cómo se comportan nuestros sistemas de software en producción.

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

proyectos Ágiles

Modelo mental #1 – El diamante de la autonomía – auto-organización – ownership

marzo 13, 2024 05:00

  • No puede haber compromiso sin ownership.
  • No puede haber ownership sin autonomía.
  • No puede haber autonomía sin propósito compartido, competencia y perímetro de actuación.
  • Hace falta DESARROLLAR a la gente y CONFIAR en ella.

Este modelo mental se encuentra explicado en las imágenes de más abajo  y en el siguiente vídeo: https://youtu.be/n7d6lJY5_ps?t=2743

Para que la autonomía de una persona o un equipo funcione, es necesario considerar varios aspectos:

  • Tener un objetivo compartido, unas expectativas acordadas entre ambas partes, que sean factibles.
  • Unas competencias que permitan que se dé esa autonomía, lo cual implica que el desarrollo de las personas en la organización (a nivel personal y profesional) sea algo clave. Y esto no se trata solamente de formación, es cuestión de dar oportunidades, acompañar, ofrecer feedback constructivo cuidando a la persona, etc.
  • Unas restricciones o límites claros (tiempos, recursos, principios, directivas o valores [E.g. Esto aquí NO lo hacemos tratando mal a la gente]).
  • La información necesaria para poder tomar buenas decisiones (a veces no se comparte lo suficiente y se acaba haciendo algo que no aporta lo suficiente). Tiene que estar fácilmente disponible, comunicada todas las veces que haga falta hasta que llegue y se entienda, suficientes conversaciones alrededor del tema con las personas relevantes e impactadas, …).

¿Cuántas veces hemos tenido problemas por no tener alguno de estos ámbitos suficientemente claros o trabajados?

Todo esto permite que la gente esté motivada y tenga más compromiso (es una consecuencia, no una exigencia), pasar del empoderamiento a las personas al “ownership” por parte de las personas, movilizar la inteligencia colectiva y que puedan avanzar con confianza si aparecen problemas, creando un círculo virtuoso de confianza mutua en la organización (y, al contrario, no hay que crear sistemas de trabajo que impliquen un castigo por el error).

Este modelo mental se puede utilizar en un workshop con un equipo o con managers. La idea es ir explicando paso a paso el modelo mental (mejor si es con una pizarra blanca en función de las aportaciones del grupo), con preguntas («¿que creéis que es necesario para…?», «¿Alguna vez os ha pasado …?», «¿Cuándo habéis visto que esto funciona y por qué?»). De este modo entre los asistentes se genera una conversación de aprendizaje: van explicando cómo ven el modelo, se cuentan historias sobre lo que les ha sucedido, que les ha funcionado (o no), cómo el contexto ha influido, etc. De este modo se enseñan unos a otros, ya que cada persona es capaz de percibir los modelos desde ángulos diferentes.

Modelos mentales:

Artículos relacionados

» 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