Metodologías ágiles. De lo racional a la inspiración.
Scrum master a tiempo completo: 42 Tareas
octubre 04, 2024 08:29
Variable not found
Enlaces interesantes 579
octubre 01, 2024 06:25
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...
- Cómo crear componentes Blazor usando directamente C# en lugar de la sintaxis Razor
José M. Aguilar - Obtener la última excepción producida en ASP.NET Core
José M. Aguilar
.NET Core / .NET
- (Non-)Nullable Reference Types in C#
Paulo Zemek - Conditional compilation symbols in C#
Bart Wullems - FSZipper in C#
Mark Seemann - Preparing for .NET 9
Mattias Karlsson - A Better Way to Handle Entity Identification in .NET with Strongly Typed IDs
Anton Martyniuk - Boosting Loop Performance in .NET: The Simple Trick of Caching Array Length
David McCarter - Mastering C# 12: New Features and How to Use Them
Cosmic Meta - .NET Terminology
Rockford Lhotka - Interact with Ollama through C#
Bart Wullems - Service Discovery in .NET
Ricardo Peres - Tired of other developers?
Stanislav Nedelchev - Implementing Blocked Floyd-Warshall algorithm for solving all-pairs shortest path problem in C#
Oleg Karasik
ASP.NET Core / ASP.NET / Blazor
- Implement a Geo-distance search using .NET Aspire, Elasticsearch and ASP.NET Core
Damien Bowden - Swagger Replacement in ASP.NET 9
Steven Giesel - Integrating the Particular Service Platform with Aspire
Jimmy Bogard - Integrating .NET Aspire With Azure Storage
Fiodar Sazanavets - Getting started with testing and .NET Aspire
Aaron Powell - Syncfusion: What's New in Blazor 2024 Volume 3
Rajendran R. - How to encrypt and decrypt data in ASP.NET Core using Data Protection API.
Hariom Dubey - ASP.NET Core 9 and IAsyncEnumerable - Async Streaming JSON and NDJSON From Blazor WebAssembly
Tomasz Pęczek - Introducing the AI-Powered Smart Blazor Components and Features
Rajendran R. - Best Practices in Building ASP.NET Core API Projects
Peter Vogel - Building Secure and Scalable APIs in .NET 8
David Ramel - Taking a look at the Problem Details enhancements in ASP.NET 9
Tim Deschryver
Azure / Cloud
- Migrate Azure VM Across Regions Using Azure CLI and Bash Script
Chris Pietschmann
Conceptos / Patrones / Buenas prácticas
- Going beyond the empty set: Embracing the power of other empty things
Raymond Chen - OpenAPI 3.1 - The Cheat Sheet
Christophe Dujarric & Yoan Gross - Interfaces Describe What - Implementations Describe How
Steve Smith - Conway's Law: The Hidden Force Shaping Your Software Architecture
Trevor I. Lasn - These 5 habits will make you a great code reviewer
Pawel Kadluczka - How To Manage Dangerous Actions In User Interfaces
Victor Ponamariov - Identity Obsession and Domain-Driven Design
Peter Ritchie
Data
- Rounding Numbers
Joe Celko - 3 Essential Techniques for Managing Transactions in EF Core
Ali Hamza Ansari - TRY/CATCH Doesn’t Always Work
Brent Ozar
Machine learning / IA / Bots
- MathPrompts Jailbreak: Cómo codificar un robo como un problema matemático para hackear a un LLM
Chema Alonso - OpenFactCheck: A Unified Framework for Factuality Evaluation of LLMs
Hasan Iqbal, Yuxia Wang 1 & more - Watermarks in preview in Azure OpenAI Service
Ken Archer - Updated production-ready Gemini models, reduced 1.5 Pro pricing, increased rate limits, and more
Logan Kilpatrick & Shrestha Basu Mallick
Web / HTML / CSS / Javascript
- Cómo optimizar imágenes y mejorar al máximo tu SEO y UX
Edgar Capafons - Augmenting the client with Vue.js
Nicolas Fränkel - Functional Web Components
Xoron - 5 Modern CSS Styles You Should Know In 2024
Poorna Theekshana - The selectmenu Element is No More…Long Live select!
Jared White - How I Implemented Full-Text Search On My Website
Milan Jovanović - Color Mixing With Animation Composition
Geoff Graham - How to Optimize Your Code with React Compiler (in Beta)
Hassan Djirdeh - How To Make A “Scroll To Select” Form Control
Preethi - How to Create a Reusable Modal Component in React
Grant Riordan - Breaking a String by Visual Width in JavaScript
Joel Ivory Johnson - Vue Basics: How to Build Complex Forms in Vue
Nada Rifki - 9 React Testing Best Practices for Better Design and Quality of Your Tests
Petar Ivanov - Creating a React TODO app in Visual Studio 2022
Sayed Ibrahim Hashimi - Parsing TAR files with Plain JavaScript
Sergio Marin - Slide Through Unlimited Dimensions With CSS Scroll Timelines
Lee Meyer - React 19: Goodbye to Old Features, Hello to the Future
Adhithi Ravichandran
Visual Studio / Complementos / Herramientas
- ReSharper 2024.3 Starts its Early Access Program!
Alexander Kurakin - Boost Your Development with Azure Tools for Visual Studio Code
Misty Miller - Next-Gen Code Coverage in Visual Studio: Enhanced C++ Support and Security
Jakub Chocholowicz - Level up your collaborations with the pull request experience in Visual Studio
Jessie Houghton - Organize Your Breakpoints like a pro
Harshada Hole - Git pull vs. git fetch: What's the difference?
GitLab
.NET MAUI / Xamarin / Mobile
- AI-Driven Smart Location Search in .NET MAUI Maps
Muniappan Subramanian - DotNetBlazor hybrid apps in Avalonia UI
Vladyslav Lubenskyi - Create Stunning Gym Subscription UI in .NET MAUI
Leomaris Reyes - HowTo: Listening to Keyboard Events and Handling Shortcuts in .NET MAUI
Joachim Leonfellner - AI-Driven Smart PDF Form Filling in .NET MAUI PDF Viewer
Deepak G. - Mastering .NET MAUI Shell—Part 3
Héctor Pérez
Otros
Publicado en Variable not found.
Variable not found
Enlaces interesantes 578
octubre 01, 2024 06:25
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...
- Atributos genéricos en C# 11
José M. Aguilar - Cacheo de porciones de vistas en ASP.NET Core MVC
José M. Aguilar
.NET Core / .NET
- Join the .NET Smart Components ecosystem
Daniel Roth - TUnit, new testing framework for .NET 8 and up.
Tom Longhurst - Disabling Recording of an Activity (span) in .NET OpenTelemetry Instrumentation
Steve Gordon - How to run .NET apps natively on Arm64 devices
Mark Downie - Understanding the behavior of the XAML Designer with abstract base classes
Peter Spada - A Modern Way to Create Value Objects to Solve Primitive Obsession in .NET
Anton Martyniuk - Using Polly For Retries
Scott Galloway - Managing TaskCancellationTokens in a central service in ASP.NET
Steven Giesel - C# 11.0 new features: ref fields and the scoped keyword
Ian Griffins - Use the implicit operator to reduce noise in your code
Josef Ottosson
ASP.NET Core / ASP.NET / Blazor
- Setting Up OpenTelemetry my .NET API
Juan Luis Guerrero - Tips for Improving API Performance in ASP.NET Core
Assis Zang - Effortlessly Visualize and Manage Data with Blazor TreeView
Keerthana Rajendran - .NET Aspire: A Game-Changer for Cloud-Native Development?
Milan Jovanović - Using Elasticsearch with .NET Aspire
Damien Bowden - API Gateway in .NET Using Ocelot
Mostafa Elnady - Blazor - Drag and Drop Modal
Ed Schimmel - Blazorise 2.0: Plans and Vision for the Future
Mladen Macanović - HTMX (and a little Alpine.js) for a SPA-like experience in ASP.NET Core
Scott Galloway - Implementing GraphQL in .NET Core
Paulo Torres - Best way Health Checks in .NET Core
Hasan Monsur
Azure / Cloud
- What is Microsoft Entra ID?
Poorna Theekshana
Conceptos / Patrones / Buenas prácticas
- Evita el acoplamiento fuerte con configurable dependency & Encapsular primitivos y colecciones
Fran Iglesias - Mediator Design Pattern in C#
Ahsan Ullah - Prototype Pattern: Cloning Objects in C#
Uday Dodiya - Understanding JWT, OAuth, and Bearer tokens
Lewis Cianci
Machine learning / IA / Bots
- New Function Calling Available in .NET for Semantic Kernel
Sergey Menshykh - Autogen RAG
Linkai Yu - Optimizing Models: Fine-Tuning, RAG and Application Strategies
Hadil BenAmor
Web / HTML / CSS / Javascript
- Introducing CSS Values and Units Level 5!
CSS WG - The Strange Behavior of the void Type in TypeScript
Ke Pi - CSS Clamp: Adjust Values Responsively
Arsalan Malik - React Styling: Essential Tips and Tricks for Designers
Prashant Yadav - Multiple Anchors
Geoff Graham - Clever Polypane Debugging Features I'm Loving
Ryan Trimble - SVG Coding Examples: Useful Recipes For Writing Vectors By Hand
Myriam Frisano - Potential Angular 19 Features and Trends
Joel Parks - Vue Basics: Deep Dive into Nuxt DevTools
Nada Rifki - A Smarter Search Dropdown with HTMX
Scott Galloway - How to Use CSS to Improve Web Accessibility
Elizabeth Lola - Most Dangerous JavaScript Vulnerabilities To Watch For in 2025
Denis Kuria
Visual Studio / Complementos / Herramientas
- Announcing Copilot Pages for multiplayer collaboration
Megan Dohnal - Improving GitHub Copilot Completions in Visual Studio for C# Developers
Mika Dumont - Multi-Project Launch Configuration in Visual Studio
Nayana Srikanth - 6 free Markdown (.md) WYSIWYG desktop Editors Part 1, Part 2 & Part 3
Mark Pelf
.NET MAUI / Xamarin
- AI-Powered Smart Searching in .NET MAUI Autocomplete
Chozarajan Pandiyarajan - Mastering .NET MAUI Shell—Part 2
Héctor Pérez
Otros
- Windows App now available on all major platforms
Hilary Braun - Announcing Swift 6
Holly Borla - Introducing the new Dev Blogs: A Modern, Streamlined, and Engaging Experience
Mathias Raacke - Definitions Lists in Markdown
Geoff Graham - Some notes on Win32 carets
Raymond Chen
Publicado en Variable not found.
Variable not found
De vuelta: Enlaces interesantes 577
octubre 01, 2024 06:25
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...
- Creación de enlaces con tag helpers de Core MVC
José M. Aguilar - Restricciones de ruta personalizadas parametrizables en ASP.NET Core
José M. Aguilar
.NET Core / .NET
- Analizando tu código sin morir en el intento
Adrián Díaz Cervera - .NET 9 Release Candidate 1 is now available!
.NET Team - Performance Improvements in .NET 9
Stephen Toub - The Best Way To Validate Objects in .NET in 2024
Anton Martyniuk - Back to Basics: Await a Task with a Timeout
Rick Strahl - Working with tar files in .NET 8
Andrew Lock - Why is F# code so robust and reliable?
Akunyili Chukwuma - What are partial classes in C# and why do we use them?
David Grace - Optimizing Hash Code Generation in .NET: A Performance Comparison
David McCarter - Thread-Safe Singleton in C#: A Guide to Double-Checked Locking and Lazy<T> Approaches
Antonio Ripa - Intersperse Values for Enumerable Collections
Khalid Abuhakmeh - Alternate Lookup for Dictionary and HashSet in .NET 9
NDepend Team - Autofixture and IOptions<T> - A Winning Combination
Adam Storr
ASP.NET Core / ASP.NET / Blazor
- How I Implemented Multiple Authentication in .NET WebAPI
Juan Luis Guerrero - ASP.NET Core Features
Ricardo Peres - Getting the ASP.NET Core Server Hosting Urls at Startup and in Requests
Rick Strahl - Blazor Basics: Testing Blazor Components with BUnit
Claudio Bernasconi - Load Testing ASP.NET Core Web API With JMeter
Muhammed Saleem - Seeding Identity Users with ASP.NET Core
Mitchel Sellers - Implement OpenID Connect Back-Channel Logout using ASP.NET Core, Keycloak and .NET Aspire
Damien Bowden - What's new for the Microsoft Fluent UI Blazor library 4.10
Vincent Baaij - Mastering CORS in .NET: 10 Expert Tips for Secure API Configuration
Sukhpinder Singh - Preventing breaking changes in public APIs with PublicApiGenerator
Andrew Lock - Caching Strategies in ASP.NET Core
Ali Hamza Ansari - ASP.NET Core Basics: Simplifying API Integration with Refit
Assis Zang
Azure / Cloud
- Introducing Blobify
Mattias Karlsson
Conceptos / Patrones / Buenas prácticas
- Claves para acceder a APIs: comodidad vs seguridad
CampusMVP - Los 10 consejos de Addy Osmani para ser mejor desarrollador
CampusMVP - Scalability Cheat Sheet
Mirco
Data
- SQL Index Rebuild vs Reorganize Comparison
Sergey Gigoyan - Reasons to Use Database Partitioning: What Is It and Why It Matters?
Trần_Tuấn_Anh - LINQ Joins on multiple columns in Entity Framework
Steven Giesel - Implementing Unit of Work Pattern in EF Core
Anton Martyniuk - Uncover SQL Server Missing Indexes
Jared Westover - How We Doubled the Performance of Our App When Using GUID/UUID Primary Keys in SQL
Matt Bentley
Machine learning / IA / Bots
- Introducing OpenAI o1
OpenAI - LLMs don't 'hallucinate'
Joe Carstairs - Bring your AI Copilots to the edge with Phi-3 and Semantic Kernel
Sophia Lagerkran & Arafat Tehsin - GitHub Models and .NET: Building Generative AI apps for engineers
April Yoho
Web / HTML / CSS / Javascript
- Sticky Headers And Full-Height Elements: A Tricky Combination
Philip Braunen - Pseudo-boolean CSS custom properties
Keith Clark - Announcing TypeScript 5.6
Daniel Rosenwasser - The Secrets of the ‘delete’ Operator in JavaScript
Zachary Lee - How fast is javascript? Simulating 20,000,000 particles
David Gerrells - What's New in JavaScript: ECMAScript 2024 (Edition 15)
Sathish Kumar Rajendran - Time Travelling CSS With :target
Lee Meyer - Two Ways To Create Custom Translated Messaging For HTML Forms
Fatuma Abdullaho - Sanding UI
Jim Nielsen - Anchor Positioning Quirks
Juan Diego Rodríguez - Vue Basics: How to Use Vue Router
Marina Mosti - Boost React MultiSelect Dropdown Performance with Virtualization
Prince Oliver - 45 JavaScript Super Hacks Every Developer Should Know
Amit Mishra - Two CSS Properties For Trimming Text Box Whitespace
Daniel Schwarz - This Typescript Behavior Will Make You Cringe
Daniel Craciun - Mastering JavaScript Event Loop and Concurrency: A Comprehensive Guide
Manish Rana - The Top 50 Tips for Better Angular Development
Joel Parks
Visual Studio / Complementos / Herramientas
- Enhancing your Visual Studio authentication experience
Ruben Rios - Github- Create a new release–The manual approach
Bart Wullems - Easily dock and float tool windows
Mads Kristensen - Incorporate GitHub Copilot into your daily flow
Rhea Patel, Sinem Akinci & Mika Dumont - Search scoping helps you find what you’re looking for
Leah Tran - Break for Async User-Unhandled exceptions in the Visual Studio Debugger
Anders Sundheim
.NET MAUI / Xamarin / Mobile
- Learn to Build Your First Blazor Hybrid App!
Sweeky Satpathy - Android Asset Packs for .NET & .NET MAUI Android Apps
Dean Ellis
Publicado en Variable not found.
Variable not found
Registro y obtención de servicios con nombre (keyed services) en .NET
octubre 01, 2024 06:05
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.
Variable not found
Novedades de System.Text.Json en .NET 9
septiembre 24, 2024 06:05
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
:
- Opciones de personalización de la indentación
- Singleton de opciones de serialización y deserialización para la web
- Soporte de anotaciones de anulabilidad
- Comprobación de parámetros obligatorios del constructor
- Descripción de tipos .NET usando JSON Schema
¡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 atrue
, por lo que la deserialización de propiedades es insensible a mayúsculas y minúsculas.JsonPropertyNamingPolicy
tiene el valorJsonNamingPolicy.CamelCase
, así que las propiedades se serializan en formato camelCase, el habitual en JavaScript y JSON.NumberHandling
esJsonNumberHandling.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!
Picando Código
Star Wars: A New Hope en concierto
septiembre 22, 2024 09:39
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.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.
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:
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:
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.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
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:
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:
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:
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.
Picando Código
Veranos con Zelda: The Legend of Zelda – A Link to the Past
septiembre 15, 2024 09:55
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.
Algo 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…
El post Veranos con Zelda: The Legend of Zelda – A Link to the Past fue publicado originalmente en Picando Código.Picando Código
¡Feliz día del programador!
septiembre 12, 2024 04:00
¡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: 2007 – 2008 – 2009 – 2010 – 2011 – 2012 – 2013 – 2014 – 2015 – 2017 – 2018 – 2019 – 2023
El post ¡Feliz día del programador! fue publicado originalmente en Picando Código.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.
Picando Código
Turrican III (Amiga) y Mega Turrican (Sega Genesis/Mega Drive)
septiembre 05, 2024 05:01
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.
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.
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.
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.
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.
Más Turrican:
- Turrican – Amiga agosto 23, 2024
- Turrican II – Amiga agosto 26, 2024
- Los secretos de Super Turrican, Mega Turrican y Turrican III agosto 27, 2024
- Turrican III (Amiga) y Mega Turrican (Sega Genesis/Mega Drive) septiembre 5, 2024
proyectos Ágiles
Master en Agile – MMA 2024-2025
septiembre 04, 2024 05:12
En octubre de 2024 se iniciará el Barcelona la 14ª edición del Postgrado en Métodos Ágiles (PMA) y otra del Máster en Transformación Agile (MMA) en La Salle (Universitat Ramon Llull), el primero a nivel mundial sobre Agile.
Con el Máster en Métodos Ágiles de La Salle-URL aprenderás a liderar el cambio hacia la Business Agility y a lanzar con éxito iniciativas en entornos complejos y altamente competitivos, reduciendo el Time To Market a fin de maximizar el valor aportado al negocio.
Desarrollarás una manera de pensar transversal e integradora para crear equipos de alto rendimiento mediante Scrum, Kanban, Lean Startup, OKR, diseño organizativo y liderazgo sistémico para elaborar estrategias de escalado Agile en la organización y transformar su cultura, de modo que también aumente la motivación de sus miembros.
Con profesores de primer nivel y visitas a empresas podrás iniciar un cambio hacia la agilidad y resiliencia empresarial en tiempos de incertidumbre.
Esta es una oportunidad única para aprender de profesionales-profesores de primer nivel, con muchos años de experiencia específica en Agile, aplicando principios y métodos ágiles en contextos diversos, especializándose en aspectos concretos, investigando sobre nuevas técnicas, ponentes en conferencias nacionales e incluso internacionales, que incluso han inventado métodos y escrito libros.
Además, aprenderás a aplicar herramientas de inteligencia artificial para afrontar retos como abordar situaciones complejas, analizar grandes volúmenes de datos, crear agendas para workshops operativos y transformadores, o preparar product backlogs.
El MMA incluye las siguientes certificaciones oficiales:
- «Certified Scrum Master» (CSM) de la Scrum Alliance, la entidad de certificación Agile de mayor prestigio a nivel internacional.
- Certified Agile Skills – Scaling 1 de la Scrum Alliance, , la entidad de certificación Agile de mayor prestigio a nivel internacional.
- Certified Leader de Agile Humans.
Adicionalmente, se incluye la visita a empresas singulares en aspectos concretos:
PMA – Postgrado en métodos Ágiles
El PMA incluye las siguientes certificaciones oficiales:
- «Certified Scrum Master» (CSM) de la Scrum Alliance.
- Opción de acceder al Certified Project, Portfolio, And Operations Management for Business Agility de Businessmap.
Asignaturas | Temas | Profesores |
Fundamentos & Inception | Equipos y Proyectos en entornos complejos. Principios y métodos más conocidos (Scrum, Lean, Kanban y XP). Facilitadores e impedimentos. Lanzamiento de Agile en un equipo. Inception y conceptualización ágil de proyecto, priorización ágil, historias de usuario, elaboración de Product Backlog, técnicas de priorización. | Xavier Albaladejo Silvia Sistaré |
Scrum y Kanban | Estimación y planificación ágil, framework de Scrum, retrospectivas, Kanban, métricas ágiles, herramientas ágiles físicas, radiadores de información. | Raul Herranz
|
Personas y equipos | Gestión de personas, gestión de conflictos, motivación e incentivos, facilitación compartida, contratación ágil.
Visual thinking. | Steven Wallace
|
Gestión de producto ágil | Design Thinking, Lean UX & Prototyping. Estrategia de Producto – Consciencia situacional (Wardley Maps), modelo de negocio (Lean Canvas), modelo de tracción, métricas AARRR. Customer development – Lanzando y escalando startups ágiles, las tres fases de un producto. Lean Startup – Desarrollo de producto basado en prototipos y experimentos. Bancos de ideas, desarrollo basado en hipótesis. | Juncal Guinea Lucía Barroso |
Ingeniería ágil | User eXperience y prototipado en Agile.
ALM ágil, eXtreme Programing, Software Craftsmanship, testing ágil. BDD y TDD. Desarrollo guiado por pruebas (de aceptación y unitarias). Métricas Accelerate y SW Delivery assessment.Cómo trabajar con código heredado y reducir la deuda técnica. DevOps | Juncal Guinea Cristina Verdi |
Trabajo Final de Postgrado | Durante el Postgrado se realiza un caso práctico de introducción de los contenidos en un equipo ágil en una empresa real. Para ellos los alumnos se organizan en equipos multidisciplinares utilizando Scrum, con feedback regular de un tutor con experiencia en transformación de equipos. |
El Postgrado tendrá una duración de 4 meses y se realizará viernes tarde y sábado por la mañana.
Ver también:
- Mejora de la situación laboral los alumnos del PMA tras un año
- Principales aspectos valorados por los alumnos del PMA
MMA – Master en Métodos Ágiles
Incluye todas las asignaturas del Postgrado (PMA) y, adicionalmente, las siguientes asignaturas especializadas en Business Agility, agilidad organizacional y transformación (aparte de las tres certificaciones indicadas al inicio y las visitas a empresas):
Asignaturas | Temas | Profesores |
Enterprise Learning & personal efficiency | Agile Kaizen, Comunidades de Práctica, Open Spaces, Talent development, gamification. Productividad y aprendizaje personal en Agile (eficiencia). | Steven Wallace Esther Somoza |
Lean Thinking & Agile Management | Lean. Escalado con Kanban. Business Agility con ViMa – agilidad para equipos de negocio Agile-Lean Management | Teodora Bozheva |
Coaching y Cultura | Coaching de equipos, creación de equipos de alto rendimiento, liderazgo.
Tipos de cultura empresarial, transformación cultural. | Joserra Díaz
|
Transformación Continua | Estrategia de despliegue de Agile en organizaciones, gestión del cambio, estructuras ágiles, cómo vender Agile a la Dirección. Contratos ágiles. Enterprise continuous improvement. | Xavier Albaladejo Ángel Medinilla |
Scaling Agile | Escalado (LESS, Spotify, Nexus, SAFe, Unfix), desescalado y auto-organización empresarial (reinventing organizations, sociocracy 3.0, liberating structures, …), equipos distribuidos.
Impact Mapping, Product Portfolio Management, Roadmapping, Budgeting for Agile | Adrian Perreau Fernando Palomo
|
Trabajo Final de Máster | Durante el Máster se realiza un caso práctico de introducción y aplicación de Agile en una empresa real, incluyendo la parte de transformación organizativa, de métodos y de cultura. Para ellos los alumnos se organizarán en equipos multidisciplinares utilizando Scrum, con feedback regular de un tutor con experiencia en transformación organizativa. | Xènia Castelltort (oratoria / public speaking para poder explicar tus ideas de manera convincente) |
El Máster tendrá una duración de 8 meses y se realizará viernes tarde y sábado por la mañana (incluye los estudios indicados en el Postgrado).
El cambio en la organización comienza por el propio cambio, para también poder dar ejemplo. Por ello en el MMA se realizan diferentes ejercicios de auto-conocimiento:
- Cómo el alumno trabaja en equipo.
- Estilo de liderazgo del alumno (según el paradigma Agile).
Como en las últimas ediciones, contaremos con la participación de empresas que nos explicarán sus experiencias de transformación y donde trabajan con modelos de gestión desescalados (basados en Sociocracia, NER y otras alternativas).
Información adicional
- Perfil de los estudiantes: 30-45 años (no son recién licenciados, son personas con experiencia profesional).
- Alrededor del 50% son mujeres.
- 15% de los estudiantes ya no son del ámbito tecnológico, son pioneros-innovadores en otras industrias.
- Alumnos de diferentes disciplinas – Product Owners, Scrum Masters, Agile Coaches, líderes de equipos, Project Managers, managers funcionales, ingenieros SW. Van a adquirir conocimientos de Agile “on-top” de todo eso (y a aprender unos de otros).
- Lo que les caracteriza: todos son agentes de cambio en su contexto (equipo, área, empresa).
- Sus 20 profesores (de reconocimiento internacional) son el MAYOR VALOR DIFERENCIAL del PMA y del MMA.
Testimoniales
Me ha permitido tener conocimientos sobre varios temas súper importantes dentro de la Transformación Digital. Me dio herramientas para crecer a Agile Coach y, además, para tener mejores conversaciones y discusiones con las empresas en donde he trabajado
Carolina Graffe
Estoy desplegando el TFM en mi empresa, Además, no estoy sola. Uno de mis compañeros del equipo ha sido contratado como consultor por mi empresa para darnos soporte. Así que no sólo estoy aplicando lo que yo aprendí, sino que el MMA me ha permitido ampliar mi círculo de contactos relevantes, que me permite seguir aprendiendo.
Susana Santillán
Estoy trabajando como agente del cambio y mis aportaciones son muy valoradas por mi jefe y compañeros. Por el feedback recibido, mis aportaciones están muy por encima de lo esperado para mi rol.
Robert Avellaneda
Tengo mucho más contexto y más herramientas para el día a día. Incluso a nivel personal también me está ayudando mucho
María Hachero
Además de los conocimientos concretos que se reciben, uno de los principales cambios que han experimentado los alumnos es mayor perspectiva en los problemas, cómo abordar la complejidad en las empresas, en su trabajo y en las relaciones entre personas y en equipos. Han ganado discurso y aplomo para defender de manera más objetiva propuestas de cambio y mejora.
Encuesta a alumnos de las ediciones anteriores:
(*) Las personas que han valorado el impacto como «neutro o poco» usualmente son perfiles muy especializados en contextos muy estáticos, con lo cual les es difícil cambiar de «profesión» e introducir cambios en sus organizaciones (aunque algunos de ellos incluso dan conferencias sobre cómo van avanzando en esos contextos tan singulares).
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.
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 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
Mega Turrican
Mega 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
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:
- Turrican – Amiga agosto 23, 2024
- Turrican II – Amiga agosto 26, 2024
- Los secretos de Super Turrican, Mega Turrican y Turrican III agosto 27, 2024
- Turrican III (Amiga) y Mega Turrican (Sega Genesis/Mega Drive) septiembre 5, 2024
Blog Bitix
Desempaquetado del ratón inalámbrico Logitech Signature M750
julio 23, 2024 09:00
Tras probar un ratón inalámbrico de los baratos pasado un tiempo me quedé con muy malas impresiones por la perdida de conectividad principalmente que era muy molesta. Pasé a un ratón con cable más fiable y tras 5 años el botón derecho me ha empezado a fallar y reconocer el clic aleatoriamente. Tras estar usando un Apple Magic Mouse que generalmente me ha funcionado bien en cuanto a conectividad he vuelto a darle una nueva oportunidad a un ratón inalámbrico pero ya de más calidad, finalmente he elegido el Logitech Signature M750. En el artículo hago un análisis del ratón y mis primeras impresiones.
Header Files
La trampa al usar semántica de movimiento con std::string
julio 16, 2024 10:00
La trampa al usar semántica de movimiento con std::string
La semántica de movimiento de std::string
puede ser complicada y, a menos que tengamos información previa sobre los tamaños esperados de las cadenas, puede tener el efecto contrario y hacer que el código sea más lento. La razón detrás de esto es la optimización de cadenas pequeñas (SSO, por sus siglas en inglés). que consiste, en resumidas cuentas, en tratar al objeto como si fuera una unión, de forma que si la cadena es más corta que un tamaño dado, se almacena en el mismo bloque de memoria del objeto en lugar de asignar memoria dinámica. Cuando la cadena supera ese tamaño, la cadena se almacena en un bloque diferente.
¿Qué es la Optimización de Cadenas Pequeñas (SSO)?
La SSO es una técnica utilizada en la implementación de std::string
para optimizar el uso de memoria y el rendimiento. En lugar de asignar memoria dinámica para todas las cadenas, la SSO almacena cadenas pequeñas directamente en el objeto std::string
(como si de una unión se tratase). Se puede ver la SSO en acción en este ejemplo.
Esta técnica evita la sobrecarga de la asignación de memoria dinámica, que puede ser costosa en términos de tiempo y recursos. Sin embargo, esta optimización introduce algunas consideraciones importantes al mover objetos std::string
.
Nota: La SSO no es parte del estándar de C++ sino más bien una optimización de algunos compiladores. Igualmente, el tamaño máximo para considerar una cadena como pequeña no tiene que ser el mismo en todas las implementaciones ni plataformas.
El constructor de movimiento de std::string
Al mover cualquier objeto en C++, estamos dando la posibilida de realizar una copia optimizada. La eficiencia aumenta cuando tenemos recursos externos que podemos intercambiar, como un puntero a un bloque de memoria o un handle de fichero. Sin embargo, para el resto de datos, aún tenemos que copiar datos. Si la cadena es pequeña y la SSO está en acción, no hay ningún puntero que intercambiar y todavía estamos copiando los datos base de std::string
.
De hecho, al mover, tenemos que garantizar que el objeto original se mantenga en un estado válido, lo cual normalmente se hace estableciendo algunos valores por defecto. En la práctica, esto significa que estamos copiando una vez y asignando una vez, duplicando la cantidad de operaciones en comparación con una copia normal. Por lo tanto, si nuestras cadenas se espera que siempre (o la mayoría del tiempo) sean más cortas que el límite de SSO, entonces un movimiento perjudicaría el rendimiento.
Comparación de Copia vs Movimiento
Para ilustrar mejor este punto, se puede comparar el rendimiento de la copia y el movimiento para cadenas pequeñas, grandes y una mezcla de ambas. El siguiente ejemplo permite visualizar las diferencias entre ellas. En este benchmark, se estableció un tamaño de 32 caracteres para tener aproximadamente un 50% de cadenas pequeñas y un 50% de cadenas grandes. Los resultados muestran cómo el movimiento de cadenas pequeñas puede ser menos eficiente que una simple copia debido a la SSO.
Conclusión
En resumen, la semántica de movimiento de std::string
no siempre es la mejor opción, especialmente cuando se trata de cadenas cortas que se benefician de la SSO. Es crucial considerar el tamaño esperado de las cadenas al decidir entre copiar o mover std::string
. Esta decisión puede tener un impacto significativo en el rendimiento de nuestra aplicación.
info.xailer.com
Plugin de despliegue de archivos
junio 11, 2024 11:35
Os presento un nuevo plugin que puede ser muy útil para todos aquellos que os dedicáis a generar ejecutables tipo CGI que luego subís a un servidor web o cualquier otro tipo de archivo que querías desplegar un vuestros servidores de forma rápida.
Su funcionamiento es muy sencillo: el plugin detecta cuando se realiza una compilación y enlazado correcto de un archivo CGI y lo sube a Internet utilizando los servicios de CURL. En Xailer 9 existe una carpeta especial para los proyectos tipo Web de nombre ‘www’. Cuando el plugin detecta que se ha realizado un salvado de algún archivo en esa carpeta, hace automáticamente el despliegue.
Es más que probable que no queramos que esté realizando el despliegue constantemente, por lo que se ha incluido una opción de menú para activarlo o desactivarlo.
Este plugin es capar de realizar un despliegue múltiple si detecta que estamos utilizando WSL para la generación de los archivos CGI para el entorno Linux (nueva función de Xailer 9). En dicho caso no sólo despliega en nuestro servidor en Internet, sino que también despliega en WSL
Este sería un ejemplo de despliegue:
Su configuración es bastante sencilla. Tan sólo hay que indicar las direcciones URL donde queremos que despliegue y nuestras credenciales.
Estas son la propiedades que hay que configurar y viendo su nombre espero que se auto-expliquen, así mismas:
- URL donde se despliegan los archivos tipo CGI
- URL donde se despliegan el resto de archivos
- Path donde se copian el resto de archivos en entornos WSL
- Extensión de archivos CGI que se reconocen
- Directorio donde se ubicarán los archivos JavaScript
- Directorio donde se ubicarán los archivos CSS
- Directorio donde se ubicarán el resto de archivos
- Nombre de usuario de la conexión FTP
- Contraseña de la conexión FTP
El plugin es susceptible de importantes mejoras. Como por ejemplo, poder establecer distintas URL y credenciales dependiendo del proyecto. Hemos decidido no incluir esa funcionalidad porque cada usuario tendrá su propia preferencia. No obstante, si alguien se anima a hacerlo, encantado de echarle una mano para cualquier duda que pueda tener.
Os adelanto que sólo funciona con Xailer 9 ya que se apoya en alguna función que no existe más que en Xailer 9.
Podéis descargar el plugin de este enlace.
Un saludo y hasta pronto
Ignacio Ortiz de Zúñiga
[Equipo de Xailer]
Juanjo Navarro
Nueva edición del Technology Radar (la 30)
mayo 21, 2024 06:31
Si no conoces el Technology Radar de la empresa Thoughtworks, deberías echarle un vistazo.
Se trata de un informe semestral donde se analizan una serie de puntos (“blips” los llaman) sobre el mundo del desarrollo de proyectos tecnológicos.
Estos blips se dividen en cuatro tipos:
- Técnicas
- Herramientas
- Plataformas
- Lenguajes & Frameworks
Para cada blip te aconsejan:
- Adoptar
- Probar
- Evaluar – mantenerse al tanto y jugar un poco con él para conocerlo.
- Resistir – mejor no usarlo, es dudoso su futuro o utilidad.
Esta última edición (la 30) está llena de IA y devops, cómo no. Yo me suelo fijar en temas prácticos (en Herramientas o en Lenguajes y Frameworks, sobre todo).
Aquí os dejo lo que más me ha llamado la atención (y he probado más o menos) de la última edición:
- Pop – Herramienta para compartir la pantalla para hacer Pair Programming.
- Aider – Una IA que hace de “coworker” de programación y me ha parecido muy bien pensado.
- Continue – Un “Github Copilot” opensource en el que puedes elegir qué LLM utilizar (con el consiguiente coste por el uso del API si es de pago, claro). Puedes también utilizar un LLM local corriendo en tu infraestructura.
- Dify – Un creador “gráfico” de aplicaciones “LLM” bastante impresionante. Permite diseñar un “flujo” de trabajo, donde vas haciendo consultas a distintos modelos IA, unir la información, hacer otras llamadas dependiendo de la respuesta anterior, etc. Además tiene integrado un sistema RAG con lo que le puedes subir documentos que la IA utilizará como referencia.
- Crabviz – Utilidad para VSCode que genera un gráfico de llamadas entre clases.
- Electric – Librería y framework que permite crear aplicaciones móviles o webapps con una base de datos “local” (que se ejecuta en el propio móvil o la página) y que automáticamente se sincroniza con un PostgreSQL en el back.
- LiteLLM – Algo así como un “proxy” LLM. Permite configurar distintos LLM y acceder a ellos con un API común.
Una sinfonía en C#
Configurar Docker + HTTPS + nginx
mayo 21, 2024 12:00
“Introducción”
Cuando queremos probar algo en local (una aplicación web), dentro de un contenedor, no podemos utilizar https como desde Visual Studio o IIS. Si necesitamos sí o sí https, debemos configurar algunas cosas, como por ejemplo, un certificado autofirmado, nginx, etc. En este post vamos a detaler cómo hacerlo.
Pasos
Vamos a necesitar hacer un par de cosas, voy a detallar los pasos a seguir en una PC con Windows y una aplicación .NET Core, es que lo que yo uso.
Básicamente pondremos nuestra aplicación en un contenedor, configuraremos nginx para que haga de proxy y que además tenga https. Luego un docker compose que levante todo.
Crear certificado autofirmado
Para crear certificados autofirmados, podemos utilizar openssl. En Windows, podemos instalarlo desde aquí.
y ejecutar este comando:
localhost.conf
[req]
default_bits = 2048
default_keyfile = localhost.key
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_ca
[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Texas
localityName = Locality Name (eg, city)
localityName_default = Dallas
organizationName = Organization Name (eg, company)
organizationName_default = localhost
organizationalUnitName = organizationalunit
organizationalUnitName_default = Development
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = localhost
commonName_max = 64
[req_ext]
subjectAltName = @alt_names
[v3_ca]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -config localhost.conf -passin pass:12345678
Esto creará dos archivos, localhost.crt y localhost.key, estos archivos los usuaremos en nginx.
Ahora necesitamos registrar el certificado como confiable ya que es auto-firmado. (es decir, registrar en Windows como confiable)
En el Administrador de Certificados (certmgr.msc), puedes encontrar esta ubicación siguiendo estos pasos:
Abrimos el Administrador de Certificados.
- Para esto escribimos certmgr.msc en el diálogo Ejecutar (Win + R).
- En el Administrador de Certificados, expande el árbol de Certificados “Usuario Actual” en el panel izquierdo.
- Debajo de esto, expande la carpeta Autoridades de Certificación Raíz Confiables.
Hacemos clic en la carpeta Certificados bajo Autoridades de Certificación Raíz Confiables.
Esta es la ubicación equivalente a Cert:\CurrentUser\Root en PowerShell.
Luego
En el Administrador de Certificados (certlm.msc, Certificate Manager for local machine), puedes encontrar esta ubicación siguiendo estos pasos:
- Abre el Administrador de Certificados para la Máquina Local. Puedes hacer esto escribiendo certlm.msc en el diálogo Ejecutar (Win + R).
- En el Administrador de Certificados, expande el árbol Certificados (Computadora Local) en el panel izquierdo.
- Debajo de esto, expande la carpeta Personal.
- Haz clic en la carpeta Certificados bajo Personal.
Ahora nginx usará los archivos de certificado y clave para servir https. Y deberías estar bien.
Configurar nginx
Para esto simplemente vamos a crear un archivo de configuración para nginx, que será el siguiente:
nginx.conf
worker_processes 1;
events { worker_connections 1024; }
http {
sendfile on;
upstream web-api {
server api:80;
}
server {
listen 80;
server_name localhost;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/ssl/certs/localhost.crt;
ssl_certificate_key /etc/ssl/private/localhost.key;
location / {
proxy_pass http://web-api;
proxy_redirect off;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $server_name;
}
}
}
Le decimos a nginx que utilice el certificado y la clave que creamos antes, y que escuche en el puerto 443. y con el proxy_pass le decimos que redirija las peticiones al servicio que escucha en el puerto 80. (más adelante ese será el nombre del servicio en el docker compose)
Ahora creamos el Dockerfile para nginx:
FROM nginx:alpine
COPY ./nginx.conf /etc/nginx/nginx.conf
COPY localhost.crt /etc/ssl/certs/localhost.crt
COPY localhost.key /etc/ssl/private/localhost.key
CMD ["nginx", "-g", "daemon off;"]
Básicamente copiamos el archivo de configuración y los archivos de certificado y clave al contenedor.
Configurar nuestra app
En este caso una simple aplicación .NET Core, que escucha en el puerto 80.
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
ENV ASPNETCORE_HTTP_PORTS 80
EXPOSE 80
EXPOSE 443
COPY --from=build /app/out ./
CMD ["dotnet", "app.dll"]
Docker compose
version: "3.7"
services:
reverseproxy:
build:
context: ./nginx
dockerfile: Dockerfile.nginx
ports:
- "8080:80"
- "1443:443"
restart: always
api:
depends_on:
- reverseproxy
build:
context: .
dockerfile: Dockerfile
ports:
- "8088:80"
restart: always
Simplemente apuntamos los dos servicios a sus Dockerfiles, y abrimos el puerto 1443 para https.
Si vemos algún error en el navegador relacionado con https lo más probable es que no hayamos registrado el certificado como confiable.
Dejo por acá un repositorio con el código
Nos leemos.
Arragonán
El lado estratégico de Domain-Driven Design. CommitConf 2024
mayo 08, 2024 12:00
Hace unas semanas estuve en Commit Conf en Madrid, evento al que no iba desde hace mucho. Estuve compartiendo la charla El lado estratégico de Domain-Driven Design, iterando ligeramente la que hice hace unos meses en La Vertical, a su vez basada en una charla más larga (y espesa) que he impartido in-company en varias ocasiones.
En los últimos años ha crecido el interés y la adopción de Domain-Driven Design en la comunidad de desarrollo de software. Ahora es bastante habitual oír hablar del lado táctico de DDD, la mayoría de las veces acompañado del uso de ports & adapters (aka Hexagonal Architecture). Pero, al menos en castellano, no he visto hablar apenas de DDD estratégico y lo que nos puede aportar a nivel de Sociotechnical Architecture.
Así que de ahí vino buena parte de mi motivación de proponer repetirla en un evento mucho más masivo como es la Commit Conf.
La presentación está dividida en 4 bloques:
- Introducción a DDD y específicamente a la parte estratégica
- Resumen de las actividades estratégicas basado en el Domain-Driven Design Starter Modelling Process de DDD Crew
- Un ejemplo práctico de DDD estratégico basado en un caso real, mostrando su división y conexión entre dominios visibilizándolo con un Context Map un tanto enriquecido con su clasificación desde diferentes puntos de vista
- Otras consideraciones a tener a nivel de la organización de equipos
Aquí os dejo el vídeo de la charla
Y el genially que usé para la presentación
Metodologías ágiles. De lo racional a la inspiración.
CAS2017: Conferencias Agile-Spain
abril 11, 2024 08:24
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.
- 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.
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:
- Modelo mental #1: AUTO-ORGANIZACIÓN / AUTONOMÍA Y OWNERSHIP.
- Modelo mental #2: GESTIÓN POR MIEDO VS CREAR UN ENTORNO SEGURO.
- Modelo mental #3: FEEDBACK AGRESIVO O PASIVO VS CLARIDAD, SINCERIDAD Y RESPETO.
Artículos relacionados
Meta-Info
¿Que es?
Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.
Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.
Idea: Juanjo Navarro
Diseño: Albin
Fuentes
- Arragonán
- Bitácora de Javier Gutiérrez Chamorro (Guti)
- Blog Bitix
- Blog de Diego Gómez Deck
- Blog de Federico Varela
- Blog de Julio César Pérez Arques
- Bloggingg
- Buayacorp
- Coding Potions
- DGG
- Es intuitivo...
- Fixed Buffer
- Header Files
- IOKode
- Infectogroovalistic
- Ingenieria de Software / Software Engineering / Project Management / Business Process Management
- Juanjo Navarro
- Koalite
- La luna ilumina por igual a culpables e inocentes
- Made In Flex
- Mal Código
- Mascando Bits
- Metodologías ágiles. De lo racional a la inspiración.
- Navegapolis
- PHP Senior
- Pensamientos ágiles
- Picando Código
- Poesía Binaria
- Preparando SCJP
- Pwned's blog - Desarrollo de Tecnologia
- Rubí Sobre Rieles
- Spejman's Blog
- Thefull
- USANDO C# (C SHARP)
- Una sinfonía en C#
- Variable not found
- Yet Another Programming Weblog
- design-nation.blog/es
- info.xailer.com
- proyectos Ágiles
- psé
- vnsjava