Logotipo Tech Writers

Escritores tecnológicos

¡Este es nuestro blog para los amantes de la tecnología! Aquí, softplayers y otros expertos comparten conocimientos fundamentales para el desarrollo de esta comunidad.

CONVIÉRTETE EN ESCRITOR TÉCNICO
RFC 9745 y su impacto en la gobernanza de API
Tech Writers Junio ​​10, 2025

RFC 9745 y su impacto en la gobernanza de API

El Internet Engineering Task Force (IETF), una organización internacional abierta que desarrolla y promueve estándares técnicos para Internet, como los protocolos TCP/IP, HTTP y DNS, acaba de publicar el RFC 9745, que define una forma estandarizada de informar la depreciación de recursos en el contexto de HTTP, lo que es especialmente relevante para las API basadas en este protocolo. En resumen, a partir de ahora los servidores podrán informar a sus clientes sobre el estado de desuso de determinados recursos mediante el encabezado de respuesta Deprecation, cuyo valor es una fecha, pasada o futura, que indica que el recurso ya ha sido o será desuso. Además, es posible utilizar el encabezado del enlace para señalar la documentación y también Sunset, proporcionando la fecha en la que el recurso dejará de estar disponible. En este artículo evaluaremos la viabilidad de aplicar este estándar en el mundo real. Utilizando las mejores prácticas en el desarrollo de API, comenzaremos con archivos de definición que siguen la especificación OpenAPI y finalizaremos con la puerta de enlace API de KrakenD. Impactos Como se mencionó, este nuevo estándar es especialmente importante para las API web, es decir, para las API que se adhieren al protocolo HTTP, como el famoso REST. En este contexto, la RFC proporciona un medio para llevar las políticas de desuso (que antes estaban restringidas al tiempo de documentación o diseño) al tiempo de ejecución. Por lo tanto, la novedad tiene el potencial de mitigar seriamente los fallos de integración, permitiendo a los desarrolladores realizar las adaptaciones necesarias con un plazo de entrega cómodo. Por cierto, vale la pena recordar que estamos entrando en la era de la IA. (con sus agentes, servidores MCP, etc.), lo que sólo aumenta el impacto de este nuevo estándar, ya que pueden aprender y adaptarse por sí mismos cuando se enfrentan a señales de depreciación. En el contexto de la gobernanza, el RFC también permite que los proveedores de API Gateway (como Kong, Tyk, KrakenD, Traefik, APISix, etc.) consideren el nuevo estándar durante los procesos de implementación de API automatizados, especialmente cuando pensamos en APIOps basado en la especificación OpenAPI. Vamos a ver. La especificación OpenAPI permite indicar la desuso de operaciones a través del campo desuso. Con este nuevo RFC, es simplemente natural pensar en vincular las cosas, es decir, hacer que la indicación de desuso presente en los archivos de definición coincida con la configuración de los gateways, los cuales, una vez en ejecución, comienzan a inyectar el nuevo encabezado de respuesta en las operaciones apropiadas. ¡Esta mejora llevaría la gobernanza al siguiente nivel de calidad! Probando el concepto Usaremos el archivo de definición que se adhiere a la Especificación OpenAPI (OAS) para describir nuestra API, construiremos un analizador en Go usando libopenapi, nos apoyaremos en KrakenD como puerta de enlace de API y en HttpBin como backend. Los detalles completos del proyecto se pueden encontrar en este repositorio. Entonces, solo resaltaré los puntos principales: Las rutas del archivo de definición (openapi.yaml): (...) /users/{userId}: (...) delete: (...) deprecated: true Tenga en cuenta que la operación de eliminación de usuario se basa en el campo estándar OAS deprecated con el valor true. Bueno, es fácil ver que nos enfrentamos a un desajuste de impedancia cuando intentamos hacer que este booleano interactúe con los nuevos encabezados proporcionados en el RFC 9745, ya que estos son mucho más ricos en información que aquel. Por razones como esta, OAS tiene extensiones que, en nuestro caso, se usarán para describir las propiedades esperadas por el RFC de la siguiente manera: paths: (...) /users/{userId}: (...) delete: (...) deprecated: true x-deprecated-at: "2025-06-30T23:59:59Z" x-deprecated-sunset: "2026-01-01T00:00:00Z" x-deprecated-link: https://api.example.com/deprecation-policy El analizador La función del analizador es leer e interpretar el archivo de definición openapi.yaml, extraer la información relevante para la puerta de enlace y crear el archivo operations.json, que se incrustará en la imagen de KrakenD y se consumirá durante su inicialización, en un enfoque llamado configuración flexible. Este es el resultado de operations.json: { "lista": [ { "ruta": "/usuarios", "método": "obtener", "backend": { "ruta": "/usuarios", "host": "http://backend:8888" } }, { "ruta": "/usuarios", "método": "publicar", "backend": { "ruta": "/usuarios", "host": "http://backend:8888" } }, { "ruta": "/usuarios/{IDusuario}", "método": "obtener", "backend": { "ruta": "/usuarios/{IDusuario}", "host": "http://backend:8888" } }, { "ruta": "/usuarios/{IDusuario}", "método": "eliminar", "obsoleto": { "en": "@1751327999", "enlace": "https://api.example.com/deprecation-policy", "sunset": "Thu, 01 Jan 2026 00:00:00 UTC" }, "backend": { "path": "/users/{userId}", "host": "http://backend:8888" } } ] } Observe que el analizador ha proyectado los elementos OAS extendidos en el archivo de configuración de KrakenD, incluidas las conversiones de valores adecuadas, de la siguiente manera: OAS KrakenD x-deprecated-at: deprecated.at: x-deprecated-link: deprecated.link: x-deprecated-sunset: deprecated.sunset: El complemento Ahora que la configuración de la puerta de enlace se ha generado correctamente a partir del archivo de definición, nuestro complemento personalizado entra en juego. Su función es identificar operaciones API obsoletas e insertar encabezados RFC 9745 con los valores apropiados. Se pueden encontrar más detalles en el repositorio de artículos. Pero una vez que el complemento se incorporó en KrakenD, obtuvimos los siguientes resultados: GET /users/1 DELETE /users/1 Tenga en cuenta que solo la segunda operación quedó obsoleta (ver operations.json) y la puerta de enlace agregó correctamente los encabezados en la respuesta. Conclusiones El experimento demostró la viabilidad del concepto, es decir, que es posible llevar las políticas de depreciación más allá de la definición y documentación, siendo fácilmente comunicadas en tiempo de ejecución. De esta forma, los sistemas pueden adoptar acciones automatizadas para comunicar la obsolescencia a las partes interesadas y reducir significativamente las posibilidades de fallas de integración. Aunque las extensiones de la Especificación OpenAPI han hecho esto posible frente a la insuficiencia del obsoleto booleano, imagino que la Iniciativa OpenAPI debería incluir una mejora en futuras versiones. Especialmente cuando pienso que Eric Wilde, coautor de este RFC, es muy activo en el mundo de las API. A los lectores que han llegado hasta aquí, muchas gracias. Espero que estas pocas palabras te hayan aportado algo y hayan hecho que tu tiempo valga la pena.

Incrustaciones: qué son y sus aplicaciones
Tech Writers Mayo 27, 2025

Incrustaciones: qué son y sus aplicaciones

Sabemos que con el surgimiento de diversas tecnologías, hay un gran aumento en la cantidad de términos que escuchamos, las incrustaciones son uno de ellos, pero ¿qué son? Embeddings, que en inglés significa “incorporar”, es un término utilizado en IA y procesamiento del lenguaje natural (PLN). Se refiere al proceso de "incrustar" o "incrustar" información compleja (como palabras, oraciones o documentos) en un espacio vectorial. Esto significa que los datos que serían difíciles de procesar directamente se transforman en una forma numérica (vectores), que los modelos de aprendizaje automático pueden entender y utilizar para tareas como la clasificación y el análisis semántico. Cuando se combinan con bases de datos vectoriales, permiten que los sistemas analicen grandes volúmenes de datos no estructurados. Esto permite la extracción de información relevante y consultas complejas de forma rápida y eficiente. Esta técnica de transformación de datos es esencial en la construcción de soluciones escalables, ya que la representación vectorial facilita la búsqueda y recuperación de información, además de comprimir la información y mantener la relación con su contenido original. Cómo funciona Sabemos que los Embeddings son vectores para la comprensión de las máquinas basadas en textos, fases, documentos. Pero ¿cómo transformamos esta información en vectores? Los vectores se forman mediante el uso de modelos de IA entrenados para identificar contextos y clasificarlos según la aproximación del contexto en números, que normalmente varían de -1 a 1. Un valor de 1 indica la coincidencia más cercana, con miles de parámetros de comparación. Estos modelos generalmente se entrenan con grandes volúmenes de texto e identifican patrones de competencia entre palabras que aparecen con frecuencia en contextos similares, como "gato" y "animal". Durante el entrenamiento, el modelo aprende a mapear estas palabras a vectores numéricos en un espacio multidimensional, de modo que las palabras con significados relacionados o contextos similares se posicionen más cerca unas de otras en este espacio vectorial. El objetivo es acercar las palabras o frases con significados similares en el "espacio" de los vectores. Por ejemplo, "gato" y "perro" deben representarse mediante vectores cercanos, mientras que "gato" y "coche" estarán más separados. Ejemplo de incrustación | Imagen: https://arize.com/blog-course/embeddings-meaning-examples-and-how-to-compute/ ¿Cómo se calcula la similitud entre dos vectores, comparando, por ejemplo, un texto con varios vectores del modelo entrenado? Matemáticamente, la técnica de similitud de coseno se utiliza normalmente para comparar dos vectores. La similitud del coseno proporciona un valor en el rango [-1,1], donde 1 es el valor de contexto más cercano y -1 el más lejano [1] Ecuación de similitud del coseno | Imagen: Wikipedia Dos vectores con 98% de similitud basado en el coseno del ángulo entre los vectores | Imagen: Incrustaciones de Richmond Alake, en la práctica Análisis de PDF con QA (preguntas y respuestas): Las incrustaciones se utilizan en sistemas de análisis de documentos, como PDF, para realizar tareas de preguntas y respuestas (QA). Las empresas que manejan grandes volúmenes de documentos, como contratos o informes, pueden utilizar incrustaciones para localizar automáticamente pasajes relevantes en un texto. Por ejemplo, al analizar un contrato en PDF, las incrustaciones permiten mapear semánticamente el contenido e identificar pasajes relacionados con preguntas como "¿Cuál es el período de validez de este contrato?" o "¿Cuáles son las obligaciones de pago del cliente?" Un modelo de IA generativa puede luego utilizar estos fragmentos para interpretar el contexto y generar respuestas en lenguaje natural con mayor precisión. Recomendación de productos (comercio electrónico): plataformas como Amazon y Netflix utilizan incrustaciones para recomendar productos o películas según las preferencias y comportamientos pasados ​​de los usuarios. Por ejemplo, al recomendar películas, se utilizan incrustaciones para capturar el estilo, el género y las características de las películas que el usuario ha visto, sugiriendo contenido nuevo según la similitud vectorial. Análisis de sentimientos (servicio al cliente): las empresas utilizan incrustaciones para analizar el sentimiento en los comentarios o mensajes de los clientes. Por ejemplo, al analizar un conjunto de comentarios en redes sociales o correos electrónicos de clientes, las incorporaciones ayudan a identificar automáticamente si el sentimiento es positivo, negativo o neutral, lo que permite una respuesta rápida y adecuada. Conclusión Las incrustaciones han demostrado ser una herramienta poderosa y en crecimiento en varias industrias, transformando la forma en que interactuamos con datos no estructurados. Su capacidad para representar numéricamente información compleja ha propiciado mejoras en los sistemas de análisis de documentos, recomendaciones e incluso en el servicio al cliente. Como tecnología en constante evolución, se espera que, con el tiempo, se integre cada vez más en soluciones inteligentes y escalables. Además, con la tendencia hacia la reducción de los costos computacionales y el avance de las infraestructuras de procesamiento y almacenamiento, se vuelve cada vez más viable escalar estas soluciones de manera eficiente y a bajo costo.

Cómo Karpenter optimizó la gestión de nuestra infraestructura EKS en AWS
Tech Writers Mayo 13, 2025

Cómo Karpenter optimizó la gestión de nuestra infraestructura EKS en AWS

Las empresas enfrentan desafíos diarios en la gestión de la infraestructura de Kubernetes, especialmente para mantener la eficiencia y reducir costos. Aquí en SoftplanDescubrimos una solución que transforma la forma en que gestionamos nuestros clústeres EKS en AWS: Karpenter. Desafíos en la gestión de instancias Antes de hablar de Karpenter, es necesario dar unos pasos atrás y explicar un poco qué es el escalado automático de nodos. Supongamos que tenemos nuestro clúster con algunas máquinas (instancias) disponibles ejecutando nuestras cargas de trabajo. ¿Qué sucede si hay un pico en el uso de nuestras aplicaciones y necesitamos lanzar más instancias (réplicas) de nuestros pods? Sin escalamiento automático, necesitaríamos aprovisionar un nodo e indicarle que se una a nuestro clúster para que nuestros pods puedan iniciarse en esta nueva instancia. Recordando que el aprovisionamiento de una instancia no es instantáneo, hay un arranque completo de la máquina, configuraciones de red y muchas otras cosas antes de que esté completamente disponible. Bien, hablamos de usuarios pico en nuestras aplicaciones, pero ¿qué pasa cuando hay inactividad? ¿Realmente queremos dejar estos nodos en funcionamiento con un poder de cómputo subutilizado? Para resolver este y otros problemas entra en juego el concepto de escaladores automáticos. Escaladores automáticos Las implementaciones de escaladores automáticos son básicamente responsables del aprovisionamiento y la consolidación de nodos. Aquí estamos hablando de escalamiento horizontal, es decir, agregar más máquinas a nuestro clúster. Hay varias implementaciones de escalamiento automático de nodos, pero en este artículo nos centraremos en la implementación de AWS y por qué decidimos migrar a otra solución. A continuación, se muestra una figura que ejemplifica cómo funciona el escalamiento automático de nodos: Figura 01: Escalamiento automático de AWS - Grupos de escalamiento automático Al definir un grupo de escalamiento en AWS, necesitamos definir varias propiedades, como el número mínimo/máximo de instancias de nodo permitidas para este grupo, los recursos utilizados, el tipo de disco, las configuraciones de red (subredes, etc.) y muchos otros detalles. Por ejemplo, para un determinado tipo de aplicación que utiliza más CPU, configuraremos un grupo que contenga tipos de instancias con más CPU que memoria. Al final posiblemente tendremos algunos grupos distintos para ciertos tipos de aplicaciones. Uniendo las piezas: Cluster Auto Scaler Para que mi clúster pueda “hablar” con mi proveedor de nube (en este ejemplo, AWS), necesitamos un componente llamado Cluster Auto Scaler o CAS. Este componente fue creado por la comunidad que mantiene Kubernetes y está disponible aquí. A continuación, se puede ver una configuración CAS predeterminada, utilizando helm para la instalación: nameOverride: cluster-autoscaler awsRegion: us-east-1 autoDiscovery: clusterName: my-cluster image: repository: registry.k8s.io/autoscaling/cluster-autoscaler tag: v1.30.1 tolerations: - key: infra operator: Exists effect: NoSchedule nodeSelector: environment: "infra" rbac: create: true serviceAccount: name: cluster-autoscaler annotations: eks.amazonaws.com/role-arn: "role-aws" extraArgs: v: 1 stderrthreshold: info ¡Con esto configurado e instalado y nuestros grupos de escalamiento automático creados, acabamos de habilitar la administración automática de nuestros nodos! Por qué decidimos migrar a Karpenter Nuestro caso de uso aquí en Projuris es el siguiente: tenemos un clúster de desarrollo y un clúster de producción. Después de migrar a Gitlab SaaS, tuvimos el desafío de cómo aprovisionar ejecutores para ejecutar nuestras canalizaciones. Se decidió que utilizaríamos el clúster de desarrollo para aprovisionar estos ejecutores. En la “primera versión” elegimos el clúster de escalador automático porque era una configuración más simple y ya cumplía con nuestra configuración de producción. Pero luego empezamos a enfrentar algunos problemas con esta elección: Tiempo de aprovisionamiento: al iniciar un pipeline, el tiempo de aprovisionamiento de la máquina era un poco lento. El punto importante es que el clúster de escalador automático paga un “peaje” al proveedor de la nube por aprovisionar un nuevo nodo. Dificultad en la configuración de grupos: como tenemos algunos “perfiles” de pipeline, esta gestión se volvió un poco complicada, porque para cada nuevo perfil se debe crear un nuevo grupo de nodos. Costo: para mitigar el problema del inicio lento de un nuevo nodo, teníamos un perfil de máquina “en línea” que siempre estaba encendido, incluso sin ejecutar ningún pipeline. ¿Qué es Karpenter? Es una solución de cluster autoescalable creada por AWS, que promete el aprovisionamiento y consolidación de nodos siempre al menor coste posible. Es lo suficientemente inteligente como para saber que, por ejemplo, al comprar una máquina bajo demanda en AWS, dependiendo de la situación, es más rentable que si fuera una máquina spot. Y esa es sólo una de las características de esta herramienta. Karpenter también trabaja con la idea de “grupos” de máquinas (que en el mundo Karpenter llamamos NodePools), pero la diferencia es que esto lo hacemos a través de CRDs (custom resource translations) del propio Karpenter, es decir, tenemos manifiestos dentro de nuestro cluster con todas estas configuraciones, eliminando la necesidad de cualquier grupo de nodos creado en AWS. pool¿Cómo nos ayudó Karpenter a superar los desafíos presentados? Tiempo de aprovisionamiento: dado que Karpenter se comunica directamente con las API del proveedor de la nube, no es necesario pagar la tarifa del clúster del escalador automático. Tuvimos muchos problemas de tiempo de espera al aprovisionar nuevos nodos; tras cambiar a Karpenter, este problema simplemente desapareció, precisamente porque el aprovisionamiento es más eficiente. Dificultad para configurar grupos: con la solución NodePools y NodeClass de Karpenter, esta configuración se volvió trivial y, lo más importante, versionada en nuestro control de versiones en Gitlab. En otras palabras, ¿es necesario incluir un nuevo perfil de máquina en el NodePool? No hay problema, solo una confirmación y Karpenter ya lo considerará en el nuevo aprovisionamiento. Costo: Pudimos usar máquinas, ya que ahora los ejecutores con características similares se asignan a nodos que cumplen con los requisitos de memoria y CPU requeridos. En otras palabras, realmente estamos utilizando toda la potencia de procesamiento que proporciona ese nodo. Esto también aplica a la consolidación de nodos. Con el escalador automático de clústeres, se requerían scripts complejos para drenar los nodos antes de la consolidación. Con Karpenter, esto se configura en el NodePool de forma muy simplificada. Un gran argumento para que la administración justifique la inversión en este tipo de cambio es el costo. A continuación, presentamos una comparación de costos utilizando Cluster AutoScaler y Karpenter en enero de 25, donde logramos un ahorro total del 16 %: Figura 02: Periodo del 01/01 al 15/01 con ClusterAutoScaler Figura 03: Periodo del 16/01 al 31/01 con Karpenter Consideraciones finales La migración a Karpenter fue una decisión acertada. Logramos simplificar la administración de nuestros nodos con diferentes perfiles de forma muy sencilla. Aún se pueden realizar algunas mejoras, como usar un único NodePool para simplificar aún más las cosas y permitir que los ejecutores configuren etiquetas específicas para el perfil de máquina que se les debe aprovisionar (más información en https://kubernetes.io/docs/reference/labels-annotations-taints/). Referencias: Karpenter (documentación oficial): https://karpenter.sh/ Node Auto Scaling (documentación oficial de k8s): https://kubernetes.io/docs/concepts/cluster-administration/node-autoscaling/

La fuerza de la colaboración y el cliente como protagonista: impactos de la evolución del producto en el Grupo Softplan
Tech Writers Abril 29, 2025

La fuerza de la colaboración y el cliente como protagonista: impactos de la evolución del producto en el Grupo Softplan

En el grupo SoftplanLa evolución del producto es un esfuerzo continuo que implica la colaboración entre equipos y un profundo compromiso con el cliente. En mi rol de Crecimiento de Producto, intercambio constantemente ideas con otros equipos y recibo comentarios valiosos de los clientes, ya sea a través del análisis de cómo usan el producto o mediante canales de comunicación específicos, como el correo electrónico. Estas interacciones me dan una visión clara del impacto que tiene la evolución continua del producto en el éxito de la empresa y el valor entregado a los clientes. Este artículo explora cómo la colaboración entre equipos y la orientación al cliente impulsan la evolución de nuestros productos y fomentan el crecimiento del Grupo. Softplan y el éxito de quienes utilizan nuestras soluciones. La colaboración entre equipos: motor de la innovación Desarrollo y mejora de productos en el Grupo Softplan Requieren una integración continua entre diferentes equipos. Las soluciones de software deben ser efectivas y estar alineadas con las demandas del mercado. Si bien no participo directamente en la definición de la hoja de ruta, mi función me permite aportar información valiosa basada en las interacciones con los clientes y los datos de rendimiento. Esto contribuye directamente a la priorización de las iniciativas de desarrollo. Estudios de Forbes indican que las empresas que fomentan la colaboración interna tienen 4,5 veces más probabilidades de retener a los mejores talentos e innovar de forma más eficiente (Forbes on Collaboration). En el grupo SoftplanLa colaboración efectiva es uno de los pilares para garantizar que las necesidades del cliente se satisfagan de forma rápida y eficiente. Las áreas de producto, marketing, crecimiento y ventas trabajan juntas continuamente, buscando siempre alinear las iniciativas con las demandas del mercado. Este trabajo colaborativo, combinado con el apoyo del equipo de Crecimiento en la priorización de iniciativas, integra diferentes perspectivas y áreas de la empresa, permitiendo ajustes constantes a los productos e impulsando la creación de innovaciones a partir de estas interacciones entre departamentos. El cliente como protagonista: la guía de nuestras decisiones en el Grupo Softplan, el cliente está en el centro de todas las decisiones, especialmente en la Unidad de Industria y Construcción, donde el valor del “cliente como protagonista” guía nuestra forma de trabajar. Utilizamos canales dedicados para recopilar comentarios continuos, y estos conocimientos dan forma a las iniciativas de productos. Como señala Salesforce, el 80% de los clientes considera que la experiencia ofrecida por una empresa es tan importante como sus productos y servicios (Salesforce State of the Connected Customer). En la práctica, esto significa que al escuchar a los usuarios y ajustar nuestros productos en función de sus demandas, fortalecemos las relaciones y aumentamos la lealtad a nuestra marca. Un ejemplo de esto fue la reciente actualización de funciones, basada en los comentarios de los clientes, que generó comunicaciones más diversificadas entre los módulos del producto, alineándose con las necesidades identificadas. Este enfoque orientado al cliente no sólo satisface las necesidades actuales, sino que también nos permite anticipar las demandas futuras. Este proceso continuo consolida nuestro papel como socio estratégico de nuestros clientes. Impacto en el mercado: Innovación y crecimiento El Grupo Softplan se destaca en el mercado por su compromiso con la innovación y enfoque en resultados concretos. Ajustar nuestros productos en función de los comentarios directos de los clientes tiene un impacto directo en el crecimiento de la empresa y la satisfacción del usuario. Como se mencionó, la actualización a comunicaciones más diversas en los módulos de productos fue una respuesta directa a estos comentarios, destacando cómo la comunicación continua con el cliente guía la evolución de nuestras soluciones. Según PwC, las empresas que priorizan la experiencia del cliente pueden ver un aumento del 16% en los ingresos y una mayor retención de clientes (Encuesta PwC sobre el futuro de la experiencia del cliente). Esta realidad también se aplica al Grupo Softplan, donde el ajuste continuo y el enfoque en las necesidades del cliente nos ayudan a ofrecer soluciones relevantes que se destacan en el mercado. El uso estratégico de los comentarios de los clientes no solo mejora la experiencia del usuario, sino que también garantiza que siempre estemos un paso adelante en términos de innovación y competitividad. Ven a crecer con nosotros El Grupo Softplan Se destaca por escuchar a sus clientes y unir a sus equipos para crear soluciones que impulsan el negocio. El valor del “cliente como protagonista” es una guía práctica y presente en nuestro viaje de evolución de producto. Colaboramos, innovamos y nos adaptamos, garantizando siempre que las necesidades del cliente estén en el centro de nuestras decisiones. Si valoras un entorno que fomenta la colaboración y la innovación, con oportunidades de aprendizaje y crecimiento continuo, el Grupo Softplan Es el lugar adecuado para usted. Aquí, nuestros valores y objetivos estratégicos se refuerzan con la formación y la oportunidad de trabajar en proyectos desafiantes que transforman el mercado del software. Únete a nosotros y forma parte de un equipo que transforma la vida de los clientes e innova el mercado. Visita nuestra página de carreras.

Evolución digital en el sector público: gestión de productos B2G
Tech Writers Abril 16, 2025

Evolución digital en el sector público: gestión de productos B2G

En los últimos años, el sector público ha ampliado sus servicios digitales para los ciudadanos. La pandemia de 2020 aceleró esta tendencia, impulsando la modernización de órganos como Tribunales de Justicia, Ministerios Públicos y Defensorías Públicas. Esta transformación pretende mejorar la eficiencia de los servicios públicos y facilitar el acceso de la población. Históricamente, las áreas de Tecnologías de la Información de estas organizaciones han adoptado modelos de gestión de proyectos que priorizan la entrega de alcances definidos, con plazos y equipos limitados a demandas específicas. Sin embargo, la creciente necesidad de agilidad ha impulsado la transición hacia la gestión de productos. En este contexto, el concepto de Business-to-Government (B2G) cobra relevancia, resaltando la importancia de la gestión de productos para ofrecer soluciones innovadoras al gobierno. Como Gerente de Producto que trabaja en productos B2G, mi objetivo es ofrecer soluciones alineadas con las necesidades de los usuarios finales. A diferencia del sector B2B, donde existe un embudo de ventas estructurado, la gestión de productos en el sector público requiere la adopción de métricas y herramientas adaptadas a este ecosistema. El día a día de los Product Managers en el sector público Las interacciones con los clientes comienzan después de la firma del contrato, cuando se produce el primer contacto con el grupo directivo, formado por los empleados responsables de la implementación del producto. A partir de este punto, se obtienen conocimientos sobre las necesidades de los usuarios finales, lo que permite una comprensión inicial del flujo de trabajo. Para priorizar el backlog, utilizamos la matriz RICE (Alcance, Impacto, Confianza, Esfuerzo), garantizando que las decisiones consideren tanto los requisitos contractuales como las necesidades de los usuarios. Esta priorización se produce de forma continua, siguiendo la evolución del producto y los contratos establecidos. En el ciclo de desarrollo aplicamos técnicas de experimentación, prototipado y pruebas de usabilidad con grupos piloto. Recopilamos datos cuantitativos y cualitativos para medir la adopción y definir mejoras en la funcionalidad del producto. Ejemplo de matriz RICE Con ​​estas premisas en mente, aplicamos a los usuarios piloto, por ejemplo, técnicas de experimentación, prototipado, realización de pruebas de usabilidad para nuevas funcionalidades. También recopilamos constantemente datos cuantitativos y cualitativos sobre el recorrido que utilizan, a medida que aumenta la adherencia. En función de las métricas recopiladas, podemos definir si es necesario mejorar las características principales o adicionales del recorrido de nuestro usuario. Ejemplo de insights cuantitativos con información del user journey en la organización de tareas utilizando la herramienta MixPanel Ejemplo de uso de la herramienta INDECX para información cualitativa sobre el producto o funcionalidad Tríada de producto entregando resultados eficientes La gestión de producto en el sector público requiere un enfoque colaborativo, integrando al equipo técnico, equipo de experiencia de usuario y cliente. Esta interacción continua fortalece la alineación estratégica y la claridad sobre la evolución del producto. La hoja de ruta del producto se comparte con el cliente para garantizar la transparencia y la previsibilidad en las entregas. Softplan se ha consolidado como referente en la transformación digital del sector público, generando impactos positivos para la ciudadanía. Soluciones como el Sistema de Automatización de Justicia (SAJ) aportan eficiencia y rapidez en los servicios públicos. Como gerente de producto en Softplan, Contribuyo a la gestión de productos dirigidos al sector público. Un ejemplo es el SAJ Defensorias, cuyo panel de tareas fue desarrollado luego del estudio de negocio y análisis técnico basado en la tríada del producto. Este tablero centraliza las actividades diarias, priorizando las tareas a realizar de inmediato y organizando las completadas para futuras referencias. Solución SAJ Softplan Nuestro objetivo es ofrecer productos intuitivos y eficientes que satisfagan las demandas diarias de los defensores públicos y contribuyan a mejorar la prestación de servicios a la sociedad. Panel de tareas del defensor en SAJ Defensorias Las iniciativas digitales en el sector público tienen un gran potencial de crecimiento, impulsado por la cultura de producto. La transformación digital es irreversible y seguirá evolucionando para satisfacer las expectativas de la sociedad de servicios más ágiles, eficientes y transparentes. Referencias bibliográficas: CAGAN, M. Inspirado: Cómo crear productos tecnológicos que los clientes adoren. Estados Unidos: Wiley, 2017. EIS, D. Gestión moderna de productos digitales. Santa Catarina: Clube de Autores, 2022. TORRES, J. Gestión de productos de software: Cómo aumentar las posibilidades de éxito de su software. São Paulo: Casa do Código, 2015. Responsabilidades del Gerente de Producto de Software en el Ciclo de Gestión de Software https://asperbrothers.com/blog/software-product-manager-resolutions/ Los diferentes tipos de 'Gerente de Producto': ¿cuál soy y cuál necesito? https://medium.com/@carlosbeneyto/types-of-product-manager-startup-3bb978f50d2f Matriz Rice: qué es y cómo mejorar la priorización de tus proyectos: https://www.nomus.com.br/blog-industrial/matriz-rice/ Aprende sobre NPS y satisfacción del cliente: https://blog.indecx.com.br/relatorios-de-nps-16-exemplos-com-indicadores-de-satisfacao-de-clientes/

Agotamiento del ThreadPool de .Net
Tech Writers Marzo 25, 2025

Agotamiento del ThreadPool de .Net

Más de una vez en mi carrera me he encontrado con este escenario: una aplicación .Net muestra frecuentemente tiempos de respuesta altos. Esta alta latencia puede tener varias causas, como un acceso lento a un recurso externo (una base de datos o una API, por ejemplo), un uso de CPU que “llega” al 100%, sobrecarga de acceso a disco, entre otras. Quiero añadir a la lista anterior otra posibilidad, a menudo poco considerada: el agotamiento del ThreadPool. Se presentará muy rápidamente cómo funciona .Net ThreadPool y ejemplos de código donde esto puede suceder. Finalmente, se demostrará cómo evitar este problema. El modelo de programación asincrónica basado en tareas de .Net es bien conocido por la comunidad de desarrollo, pero creo que sus detalles de implementación son poco comprendidos, y es en los detalles donde reside el peligro, como dice el refrán. Detrás del mecanismo de ejecución de Tareas .Net hay un Scheduler, encargado, como su nombre indica, de programar la ejecución de Tareas. A menos que se cambie explícitamente, el programador .Net predeterminado es ThreadPoolTaskScheduler, que, como su nombre lo indica, utiliza el ThreadPool .Net predeterminado para realizar su trabajo. El ThreadPool luego administra, como se esperaba, una pool de hilos, a los cuales asigna las Tareas que recibe mediante una cola. Es en esta cola donde se almacenan las tareas hasta que haya un hilo libre en la cola. pooly luego comenzar a procesarlo. De forma predeterminada, el número mínimo de subprocesos pool es igual al número de procesadores lógicos en el host. Y aquí está el detalle de cómo funciona: cuando hay más tareas a ejecutar que el número de subprocesos en el poolEl ThreadPool puede esperar a que un hilo quede libre o crear más hilos. Si decide crear un nuevo hilo y si el número actual de hilos en el pool es igual o mayor que el número mínimo configurado, este crecimiento demora entre 1 y 2 segundos por cada nuevo hilo agregado al pool. Nota: A partir de .Net 6, se introdujeron mejoras en este proceso, lo que permitió un aumento más rápido en la cantidad de subprocesos en ThreadPool, pero la idea principal sigue siendo la misma. Veamos un ejemplo para que quede más claro: supongamos que una computadora tiene 4 colores. El valor mínimo del ThreadPool será 4. Si todas las tareas entrantes procesan rápidamente su trabajo, el pool Incluso puede tener menos del mínimo de 4 hilos activos. Ahora, imaginemos que 4 Tareas de duración ligeramente mayor llegan simultáneamente, utilizando así todos los hilos de la pool. Cuando la siguiente tarea llega a la cola, deberá esperar entre 1 y 2 segundos, hasta que se agregue un nuevo hilo a la cola. pool, luego salga de la cola y comience el procesamiento. Si esta nueva Tarea también tiene una duración mayor, las siguientes Tareas volverán a esperar en la cola y deberán “pagar el peaje” de 1 a 2 segundos antes de poder comenzar a ejecutarse. Si este comportamiento de las nuevas tareas de larga ejecución continúa durante algún tiempo, la sensación para los clientes de este proceso será de lentitud, para cualquier nueva tarea que llegue a la cola de ThreadPool. Este escenario se llama agotamiento de ThreadPool o inanición de ThreadPool. Esto sucederá hasta que las tareas terminen su trabajo y comiencen a devolver subprocesos a pool, permitiendo la reducción de la cola de Tareas pendientes, o que la pool Puede crecer lo suficiente para satisfacer la demanda actual. Esto puede tardar varios segundos, dependiendo de la carga, y solo entonces dejará de existir la desaceleración observada anteriormente. Código sincrónico vs. código asincrónico Ahora debemos hacer una distinción importante entre los tipos de trabajos de larga duración. Generalmente se pueden clasificar en dos tipos: limitados por CPU/GPU (CPU-bound o GPU-bound), como ejecutar cálculos complejos, o limitados por E/S (I/O-bound), como acceder a bases de datos o llamadas de red. En el caso de tareas limitadas por la CPU, a excepción de las optimizaciones de algoritmos, no hay mucho que se pueda hacer: es necesario tener suficientes procesadores para satisfacer la demanda. Pero, en el caso de tareas limitadas por E/S, es posible liberar el procesador para responder a otras solicitudes mientras se espera que se complete la operación de E/S. Y eso es exactamente lo que hace ThreadPool cuando se utilizan API de E/S asincrónicas. En este caso, incluso si la tarea específica aún consume mucho tiempo, el hilo volverá al pool y puede atender otra tarea en la cola. Cuando se complete la operación de E/S, la tarea se volverá a poner en cola y luego continuará ejecutándose. Para obtener más detalles sobre cómo ThreadPool espera a que finalicen las operaciones de E/S, haga clic aquí. Sin embargo, es importante tener en cuenta que todavía hay API de E/S sincrónicas que hacen que el hilo se bloquee y evitan que se libere al pool. Estas API -y cualquier otro tipo de llamada que bloquee un hilo antes de volver a la ejecución- comprometen el correcto funcionamiento del ThreadPool, y pueden provocar que se agote al someterse a cargas suficientemente grandes y/o prolongadas. Podemos decir entonces que ThreadPool –y por extensión ASP.NET Core/Kestrel, diseñado para operar de forma asincrónica– está optimizado para ejecutar tareas de baja complejidad computacional, con cargas de E/S limitadas de forma asincrónica. En este escenario, una pequeña cantidad de subprocesos es capaz de procesar una gran cantidad de tareas/solicitudes de manera eficiente. Bloqueo de subprocesos con ASP.NET Core Veamos algunos ejemplos de código que provocan el bloqueo de subprocesos en ASP.NET Core. pool, utilizando ASP.NET Core 8. Nota: Estos códigos son ejemplos simples y no pretenden representar ninguna práctica, recomendación o estilo en particular, excepto los puntos relacionados específicamente con la demostración de ThreadPool. Para mantener un comportamiento idéntico entre los ejemplos, se utilizará una solicitud a una base de datos de SQL Server que simulará una carga de trabajo que tarda 1 segundo en regresar, utilizando la instrucción WAITFOR DELAY. Para generar una carga de uso y demostrar los efectos prácticos de cada ejemplo, utilizaremos siege, una utilidad de línea de comandos gratuita diseñada para este propósito. En todos los ejemplos, se simulará una carga de 120 accesos simultáneos durante 1 minuto, con un retraso aleatorio de hasta 200 milisegundos entre solicitudes. Estos números son suficientes para demostrar los efectos en el ThreadPool sin generar tiempos de espera al acceder a la base de datos. Versión sincrónica Comencemos con una implementación completamente sincrónica: la acción DbCall es sincrónica y el método ExecuteNonQuery de DbCommand/SqlCommand es sincrónico, por lo que bloqueará el hilo hasta que la base de datos regrese. A continuación se muestra el resultado de la simulación de carga (con el comando de asedio utilizado). Puedes ver que logramos una tasa de 27 solicitudes por segundo (tasa de transacción) y un tiempo de respuesta promedio (tiempo de respuesta) de alrededor de 4 segundos, donde la solicitud más larga (transacción más larga) duró más de 16 segundos, un rendimiento muy pobre. Versión asincrónica – Intento 1 Ahora usemos una acción asincrónica (devolviendo la tarea) ), pero aún utiliza el método sincrónico ExecuteNonQuery. Ejecutando el mismo escenario de carga que antes, tenemos el siguiente resultado. Cabe destacar que el resultado fue aún peor en este caso, con una tasa de solicitudes de 14 por segundo (en comparación con 27 para la versión completamente sincrónica) y un tiempo de respuesta promedio de más de 7 segundos (en comparación con 4 para la anterior). Versión asincrónica – Intento 2 En esta próxima versión, tenemos una implementación que ejemplifica un intento común –y no recomendado– de transformar una llamada de E/S sincrónica (en nuestro caso, ExecuteNonQuery ) en una “API asincrónica”, usando Task.Run. Después de la simulación, el resultado está cerca de la versión sincrónica: tasa de solicitudes de 24 por segundo, tiempo de respuesta promedio de más de 4 segundos y la solicitud más larga tardó más de 14 segundos en regresar. Versión asincrónica – Intento 3 Ahora la variación conocida como “sync over async”, donde usamos métodos asincrónicos, como ExecuteNonQueryAsync en este ejemplo, pero se llama al método .Wait() de la Tarea devuelta por el método, como se muestra a continuación. Tanto la propiedad .Wait() como la .Result de una Tarea tienen el mismo comportamiento: ¡hacen que el hilo en ejecución se bloquee! Ejecutando nuestra simulación, podemos ver a continuación como el resultado también es malo, con una tasa de 32 solicitudes por segundo, un tiempo promedio de más de 3 segundos, y solicitudes que tardan hasta 25 segundos en regresar. No es sorprendente que se desaconseje el uso de .Wait() o .Result en una tarea en código asincrónico. Problema Solución Finalmente, veamos el código creado para trabajar de la manera más eficiente, a través de APIs asíncronas y aplicando async/await correctamente, siguiendo la recomendación de Microsoft. Luego tenemos la acción asincrónica, con la llamada ExecuteNonQueryAsync con await. El resultado de la simulación habla por sí solo: tasa de solicitudes de 88 por segundo, tiempo de respuesta promedio de 1,23 segundos y solicitud que tarda un máximo de 3 segundos en regresar: números en general tres veces mejores que cualquier opción anterior. La tabla a continuación resume los resultados de las diferentes versiones, para una mejor comparación de los datos entre ellas. Código VersiónTasa de Solicitud ( /s)Tiempo Promedio (s)Tiempo Máximo (s)Sincrónico27,384,1416,93Asincrónico114,337,9414,03Asincrónico224,904,5714,80Asincrónico332,433,5225,03Solución88,911,233,18 Solución Alternativa Cabe mencionar que podemos configurar el ThreadPool para tener un número mínimo de hilos mayor al predeterminado (el número de procesadores lógicos). Con esto podrá aumentar rápidamente el número de hilos sin pagar ese “peaje” de 1 o 2 segundos. Hay al menos tres formas de hacer esto: mediante configuración dinámica, utilizando el archivo runtimeconfig.json, mediante configuración del proyecto, ajustando la propiedad ThreadPoolMinThreads, o mediante código, llamando al método ThreadPool.SetMinThreads. Esto debe verse como una medida temporal, mientras no se realizan los ajustes adecuados al código como se muestra arriba, o después de pruebas previas apropiadas para confirmar que trae beneficios sin efectos secundarios en el rendimiento, como recomienda Microsoft. Conclusión El agotamiento de ThreadPool es un detalle de implementación que puede tener consecuencias inesperadas. Y pueden ser difíciles de detectar si tenemos en cuenta que .Net tiene varias formas de obtener el mismo resultado, incluso en sus APIs más conocidas –creo que motivado por años de evolución del lenguaje y de ASP.NET, siempre apuntando a la compatibilidad hacia atrás. Cuando hablamos de operar a ritmos o volúmenes crecientes, como pasar de decenas a cientos de solicitudes, es fundamental conocer las últimas prácticas y recomendaciones. Además, conocer uno u otro detalle de implementación puede marcar la diferencia a la hora de evitar problemas de escala o diagnosticarlos más rápidamente. Tech Writers. En un artículo futuro, exploraremos cómo diagnosticar el agotamiento de ThreadPool e identificar la fuente del problema en el código de un proceso en ejecución.