<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Johan Garcia</title>
    <description>The latest articles on DEV Community by Johan Garcia (@devjohanadrian).</description>
    <link>https://dev.to/devjohanadrian</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1330042%2Fe604656f-104b-4279-8285-06c5e42d59be.png</url>
      <title>DEV Community: Johan Garcia</title>
      <link>https://dev.to/devjohanadrian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devjohanadrian"/>
    <language>en</language>
    <item>
      <title>El problema de la confianza ciega: cómo reducir las alucinaciones en agentes de IA parte 2</title>
      <dc:creator>Johan Garcia</dc:creator>
      <pubDate>Tue, 14 Jul 2026 04:33:38 +0000</pubDate>
      <link>https://dev.to/devjohanadrian/el-problema-de-la-confianza-ciega-como-reducir-las-alucinaciones-en-agentes-de-ia-parte-2-aa0</link>
      <guid>https://dev.to/devjohanadrian/el-problema-de-la-confianza-ciega-como-reducir-las-alucinaciones-en-agentes-de-ia-parte-2-aa0</guid>
      <description>&lt;p&gt;En una arquitectura multiagente típica, el Orchestrator delega tareas a agentes especializados y procesa sus respuestas. El problema aparece cuando un agente devuelve una salida mal formada: XML con etiquetas desbalanceadas, JSON inválido, campos obligatorios ausentes o tipos de datos incorrectos. En estos casos, el Orchestrator no siempre puede detectar el error de forma confiable, lo que provoca fallos silenciosos y aumenta la probabilidad de alucinaciones.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Plantillas de datos estructurados y Output Contracts para reducir alucinaciones&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Los Output Contracts son una estrategia de validación estructurada para la comunicación entre agentes y el Orchestrator en arquitecturas multiagente. Consisten en encapsular la respuesta de cada agente dentro de un envelope XML que contiene un payload JSON validado mediante un JSON Schema específico para ese agente.&lt;/p&gt;

&lt;p&gt;Un Output Contract define de forma explícita el formato que el agente debe producir. Mientras que los system prompts establecen reglas de comportamiento, los contratos de salida eliminan la ambigüedad sobre la estructura de la respuesta.&lt;/p&gt;

&lt;p&gt;En un sistema multiagente, un output es el input del siguiente agente. Si ese output no respeta un formato conocido, el agente receptor puede interpretar la información de manera incorrecta, y es precisamente en esa interpretación donde suelen aparecer las alucinaciones de acción. Al establecer un contrato de formato entre subagentes, ese margen de interpretación desaparece, reduciendo errores sin necesidad de añadir lógica adicional de validación en cada paso.&lt;/p&gt;

&lt;p&gt;Los tres bloques que componen un Output Contract son:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdwjzra2sfzrv4xbjjiue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdwjzra2sfzrv4xbjjiue.png" alt="Prompt contract" width="744" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Arquitectura&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;El sistema está compuesto por:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un Contract Validator encargado de analizar y validar las respuestas.&lt;/li&gt;
&lt;li&gt;Un schema base con los campos comunes.&lt;/li&gt;
&lt;li&gt;Un schema específico por agente (Developer, Planner, Reviewer, Orchestrator, etc.).&lt;/li&gt;
&lt;li&gt;Un conjunto de pruebas automatizadas para verificar el comportamiento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;El flujo de validación consiste en:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extraer el envelope XML.&lt;/li&gt;
&lt;li&gt;Parsear el JSON.&lt;/li&gt;
&lt;li&gt;Validar los campos base.&lt;/li&gt;
&lt;li&gt;Validar el payload contra el schema del agente.&lt;/li&gt;
&lt;li&gt;Retornar un resultado indicando si el contrato es válido. &lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Implementación paso a paso&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Paso 1: Crear el Schema base&lt;/strong&gt;&lt;br&gt;
El primer paso consiste en definir un Schema base con los campos obligatorios que debe incluir toda respuesta generada por un agente. Este esquema representa la estructura mínima del output y sirve como punto de partida para que todos los subagentes compartan un formato consistente antes de aplicar las validaciones específicas de cada rol.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcp0cxdu881rgamm3het9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcp0cxdu881rgamm3het9.png" alt="Schema base" width="744" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paso 2: Crear Schemas específicos por agente&lt;/strong&gt;&lt;br&gt;
Cada agente requiere reportar información distinta según las responsabilidades definidas en su system prompt. Por ello, cada uno cuenta con un Schema específico que amplía el Schema base, incorporando únicamente los campos necesarios para ese rol. De esta forma, se mantiene una estructura común para todos los agentes sin perder la flexibilidad de validar respuestas especializadas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F39jxbs6bo8qde4pnvhhz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F39jxbs6bo8qde4pnvhhz.png" alt="developer agent schema" width="800" height="998"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paso 3: Modificar los system prompts de los agentes (formato del envelope)&lt;/strong&gt;&lt;br&gt;
En este paso se modifican los system prompts de los agentes que deberán responder utilizando el formato definido por el Output Contract. En este ejemplo, se actualizará el Developer, indicándole explícitamente que todas sus respuestas deben ajustarse al envelope establecido y referenciando la ubicación del Schema específico del agente para que pueda generar un output válido.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa2upfvbxt44ztg0ypwoq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa2upfvbxt44ztg0ypwoq.png" alt=" " width="744" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paso 4: Crear el validador (&lt;code&gt;contractValidator.js&lt;/code&gt;)&lt;/strong&gt;&lt;br&gt;
Una vez definidos los &lt;em&gt;Schemas&lt;/em&gt; y configurados los &lt;em&gt;system prompts&lt;/em&gt;, el siguiente paso es implementar el &lt;strong&gt;Contract Validator&lt;/strong&gt;. Este componente será el encargado de recibir la respuesta del agente, extraer el &lt;em&gt;envelope&lt;/em&gt; XML, parsear el &lt;em&gt;payload&lt;/em&gt; JSON y validar tanto el &lt;strong&gt;Schema base&lt;/strong&gt; como el &lt;em&gt;Schema&lt;/em&gt; específico del agente. Si el contrato es válido, la respuesta podrá continuar con el flujo de ejecución; de lo contrario, se devolverán los errores de validación correspondientes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn0w6bnteouhd77rs0v0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn0w6bnteouhd77rs0v0v.png" alt=" " width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con esto validamos, en tiempo real, que la respuesta de cada agente cumpla con el contrato definido.&lt;/p&gt;

&lt;p&gt;Esta implementación es solo un ejemplo. Si deseas ver el contenido completo del validador, puedes consultarlo en &lt;a href="https://gist.github.com/DevJohanAdrian/ac9b7aaf0d95b232a528ab3e71780c0a" rel="noopener noreferrer"&gt;contractValidator.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paso 4.5: Invocar el validador&lt;/strong&gt;&lt;br&gt;
Existen dos formas de validar el output de cada agente utilizando contractValidator.js:&lt;/p&gt;

&lt;p&gt;Usar el hook nativo tool.execute.after de OpenCode. Esta sería la solución más limpia y apropiada, ya que permitiría ejecutar automáticamente contractValidator.js después de cada respuesta del agente. Sin embargo, actualmente esta opción está bloqueada debido al *&lt;em&gt;Blocked by OpenCode Issue #25918&lt;/em&gt;, por lo que, de momento, no es viable.&lt;/p&gt;

&lt;p&gt;Realizar la validación desde el system prompt. Como alternativa temporal, el propio agente invoca contractValidator.js, enviando su output para ser validado. En la práctica, esta estrategia emula el comportamiento que tendría tool.execute.after y podrá reemplazarse por el hook nativo cuando este esté disponible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F04hvkvjy3zxsvwrlcwmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F04hvkvjy3zxsvwrlcwmz.png" alt=" " width="744" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando el agente genera una respuesta, el proceso de validación sigue el siguiente flujo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se extrae el contenido del bloque .&lt;/li&gt;
&lt;li&gt;Se parsea el payload JSON.&lt;/li&gt;
&lt;li&gt;Se carga el Schema correspondiente al agente.&lt;/li&gt;
&lt;li&gt;Se ejecuta validatePayload(payload, schema).&lt;/li&gt;
&lt;li&gt;Si la validación falla, la ejecución se detiene y se solicita al agente generar nuevamente la respuesta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;¿Por qué hacerlo? Porque permite detectar errores de formato antes de que la respuesta continúe en el flujo de trabajo, garantizando consistencia entre agentes y reduciendo la propagación de errores.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paso 5: Validar la respuesta del agente&lt;/strong&gt;&lt;br&gt;
Todo comienza con una única cadena de texto (raw input): la respuesta que produce el agente. A partir de esta salida, el validador extrae el contrato, interpreta su contenido y verifica que cumpla con la estructura esperada.&lt;/p&gt;

&lt;p&gt;A continuación veremos un ejemplo real de la respuesta generada por un Developer después de implementar un middleware de autenticación basado en JWT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmvamy50kviwco1dbb8bh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmvamy50kviwco1dbb8bh.png" alt=" " width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En este ejemplo pueden identificarse claramente las partes que conforman un Output Contract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Etiqueta XML (): marca el inicio y el final del bloque estructurado. Corresponde al formatting prompt y permite localizar de forma confiable el contenido que debe validarse.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JSON interno: contiene el payload con la información estructurada que el resto del flujo puede consumir de manera fiable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Campos fijos (agent, timestamp, version, etc.): pertenecen al Schema base y garantizan que el Orchestrator o cualquier otro agente disponga siempre de la misma información para continuar el flujo de trabajo.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;¿Qué estamos ganando con esta estrategia?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Antes (solo texto libre)&lt;/strong&gt;&lt;br&gt;
Sin un Output Contract, cada agente responde en lenguaje natural y el Orchestrator debe interpretar qué quiso decir. Esto genera múltiples problemas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No existe un formato garantizado para las respuestas.&lt;/li&gt;
&lt;li&gt;Cada agente puede estructurar la información de forma diferente.&lt;/li&gt;
&lt;li&gt;Un JSON inválido o un XML mal formado puede romper todo el flujo.&lt;/li&gt;
&lt;li&gt;El Orchestrator debe asumir e interpretar datos, aumentando las probabilidades de alucinación.&lt;/li&gt;
&lt;li&gt;Los errores suelen detectarse tarde, cuando ya se propagaron al resto de agentes.&lt;/li&gt;
&lt;li&gt;Integrar nuevos subagentes requiere adaptar constantemente la lógica de interpretación.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foe90q4bw99hei18xghs6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foe90q4bw99hei18xghs6.png" alt=" " width="744" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Después (Markdown + Output Contract)&lt;/strong&gt;&lt;br&gt;
Con un Output Contract, el agente deja de responder con texto libre y entrega una estructura predecible y validable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Qué cambia?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El Orchestrator ya no necesita interpretar el texto para saber qué ocurrió.&lt;/li&gt;
&lt;li&gt;El estado de la ejecución, los errores y el resultado vienen en campos explícitos.&lt;/li&gt;
&lt;li&gt;Cada respuesta sigue exactamente el mismo formato.&lt;/li&gt;
&lt;li&gt;El contrato puede validarse automáticamente antes de continuar el flujo.&lt;/li&gt;
&lt;li&gt;Los agentes consumidores reciben datos consistentes, reduciendo las alucinaciones y los errores en cascada.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El Orchestrator deja de "adivinar" el significado de la respuesta y pasa a trabajar con datos estructurados y confiables. Esto hace que la comunicación entre agentes sea más robusta, predecible y fácil de mantener, especialmente a medida que la arquitectura crece en complejidad.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq992pvop28j0soeskkpz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq992pvop28j0soeskkpz.png" alt=" " width="744" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El resultado&lt;/strong&gt;&lt;br&gt;
La respuesta sigue siendo igual de legible para una persona; continúas leyendo el mismo texto generado por el agente. La diferencia es que, al final, se incluye un pequeño bloque estructurado (Output Contract) que el Orchestrator procesa internamente.&lt;/p&gt;

&lt;p&gt;De esta forma, humanos y agentes consumen la misma respuesta, pero cada uno utiliza la parte que le corresponde: el desarrollador lee el contenido en lenguaje natural, mientras que el Orchestrator interpreta el contrato estructurado para continuar el flujo de trabajo de forma segura y consistente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh99y3eqw0ej0p2ey48fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh99y3eqw0ej0p2ey48fw.png" alt=" " width="744" height="270"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Qué mejora en la experiencia?&lt;/strong&gt;&lt;br&gt;
Si el Orchestrator puede leer esos datos estructurados, deja de depender de interpretar texto libre y puede ofrecer respuestas mucho más inteligentes y precisas. Por ejemplo, puede:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detectar automáticamente si una tarea finalizó con éxito o falló.&lt;/li&gt;
&lt;li&gt;Identificar el agente que produjo la respuesta y actuar en consecuencia.&lt;/li&gt;
&lt;li&gt;Mostrar errores claros y contextualizados sin analizar lenguaje natural.&lt;/li&gt;
&lt;li&gt;Reintentar únicamente la tarea que falló, en lugar de reiniciar todo el flujo.&lt;/li&gt;
&lt;li&gt;Encadenar agentes de forma más confiable al consumir datos validados.&lt;/li&gt;
&lt;li&gt;Generar métricas, auditorías y trazabilidad de cada ejecución.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En otras palabras, los Output Contracts no solo reducen las alucinaciones, sino que también mejoran la confiabilidad, la observabilidad y la experiencia general de trabajar con arquitecturas multiagente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F98fcc3jabv1w6jn5g43e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F98fcc3jabv1w6jn5g43e.png" alt=" " width="744" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;En resumen&lt;/strong&gt;&lt;br&gt;
No pierdes legibilidad; ganas automatización.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tú sigues leyendo un Markdown claro, estructurado y fácil de entender.&lt;/li&gt;
&lt;li&gt;El Orchestrator consume el JSON del Output Contract, lo valida y puede gestionar el flujo de trabajo de forma profesional, sin depender de interpretar texto libre ni de cometer errores de interpretación.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En definitiva, una misma respuesta satisface dos necesidades: una experiencia de lectura cómoda para las personas y un formato estructurado y confiable para los agentes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>agents</category>
      <category>programming</category>
    </item>
    <item>
      <title>El problema de la confianza ciega: cómo reducir las alucinaciones en agentes de IA parte 1</title>
      <dc:creator>Johan Garcia</dc:creator>
      <pubDate>Fri, 03 Jul 2026 07:10:07 +0000</pubDate>
      <link>https://dev.to/devjohanadrian/el-problema-de-la-confianza-ciega-como-reducir-las-alucinaciones-en-agentes-de-ia-parte-1-2aah</link>
      <guid>https://dev.to/devjohanadrian/el-problema-de-la-confianza-ciega-como-reducir-las-alucinaciones-en-agentes-de-ia-parte-1-2aah</guid>
      <description>&lt;p&gt;Dentro de lo que una alucinación puede hacer, encontramos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Problemas de seguridad: Supply chain security problems, AI package hallucination.&lt;/li&gt;
&lt;li&gt;También podemos encontrar los problemas de toda la vida: mala implementación de requerimientos por falta de controles.&lt;/li&gt;
&lt;li&gt;Llamados incorrectos a tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estaremos viendo varias estrategias y la aplicación de técnicas de prompt engineering orientadas a la reducción de alucinaciones en los LLMs (Large Language Models). Nos enfocaremos en la aplicación de agentes, subagentes y su orquestación.&lt;/p&gt;

&lt;p&gt;Como consideración, algunas de las estrategias estarán directamente ligadas a la creación de archivos de contexto en Markdown. Estos archivos, al ser leídos por el LLM de turno, inyectarán su contenido en la context window del modelo, haciendo que el LLM disponga de nuevo contexto. A continuación veremos cómo aprovechar esto mediante las siguientes estrategias.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;AGENTS.md y CLAUDE.md&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Estos dos son los más conocidos hasta el momento, pero existen diferentes estándares dependiendo de la compañía o la herramienta que estemos usando. Entre ellos se encuentran:&lt;/p&gt;

&lt;h2&gt;
  
  
  Agentes de terminal y CLI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CLAUDE.md: El estándar oficial y nativo de Claude Code (la herramienta de línea de comandos de Anthropic).&lt;/li&gt;
&lt;li&gt;AGENTS.md: El estándar universal y abierto, compatible con múltiples agentes autónomos dentro del ecosistema open source.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Editores de código e IDEs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;.cursorrules: Utilizado por Cursor. Es el archivo más popular para proporcionar instrucciones globales de estilo y comportamiento al chat y al modo Composer dentro de este editor.&lt;/li&gt;
&lt;li&gt;.copilotrules: Utilizado por GitHub Copilot (en VS Code y entornos JetBrains) para personalizar las respuestas del chat del copiloto.&lt;/li&gt;
&lt;li&gt;.roo-cline-rules: Utilizado por Roo Cline (anteriormente Cline), una extensión avanzada de agente autónomo para VS Code.&lt;/li&gt;
&lt;li&gt;.windsurfrules: Utilizado por Windsurf, el IDE de Codeium enfocado en flujos de trabajo con agentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Plataformas de repositorios (contexto web)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;.github/copilot-instructions.md: Ubicación alternativa oficial que GitHub lee automáticamente para enriquecer el contexto de Copilot dentro de su plataforma web y en los pull requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Un truco profesional de configuración&lt;/strong&gt;&lt;br&gt;
Si utilizas varias herramientas al mismo tiempo (por ejemplo, programas con Cursor, pero ejecutas comandos con Claude Code desde la terminal), no necesitas copiar y pegar el mismo contenido en cuatro archivos diferentes.&lt;/p&gt;

&lt;p&gt;Puedes crear un único archivo centralizado (como AGENTS.md) y utilizar enlaces simbólicos (symlinks) para que los demás archivos se actualicen automáticamente. Algunas estrategias son las siguientes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1fs2hsp85z6jqbh1y9y4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1fs2hsp85z6jqbh1y9y4.png" alt="AGENTS.md" width="790" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora bien, en lo que nos concierne como desarrolladores, ¿cómo disminuimos las alucinaciones utilizando esta estrategia?&lt;/p&gt;

&lt;p&gt;Gestión del contexto: A medida que un proyecto crece y se agregan nuevas funcionalidades, los modelos de IA tienden a perder contexto. Como consecuencia, pueden sobrescribir código que ya funcionaba, romper reglas de negocio o proponer implementaciones inconsistentes.&lt;/p&gt;

&lt;p&gt;Uso de archivos de contexto (CLAUDE.md, AGENTS.md, etc.): Un ingeniero de software no depende únicamente de prompts. Utiliza archivos de configuración para definir la arquitectura, las convenciones, las restricciones y las reglas del proyecto. De esta forma, la IA trabaja dentro de un marco conocido y tiene menos margen para desviarse o inventar soluciones.&lt;/p&gt;

&lt;p&gt;Pensar en restricciones, no en prompts: La diferencia entre un usuario y un ingeniero no está en escribir mejores prompts, sino en diseñar un sistema con reglas claras. Cuantas más restricciones tenga el modelo sobre cómo debe trabajar, menor será la probabilidad de que alucine o genere cambios incompatibles con la arquitectura.&lt;/p&gt;

&lt;p&gt;En otras palabras, un buen archivo de contexto tiene mucho más impacto que cientos de prompts aislados. En lugar de repetir instrucciones en cada conversación, se establece un marco de trabajo consistente que guía a la IA, reduce las alucinaciones y facilita detectar comportamientos incorrectos mucho antes de que lleguen a producción.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Typist y Architect&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Cuando se le pide a un agente: "implementa el sistema de autenticación", el LLM debe tomar decisiones de arquitectura, diseño, estructura de carpetas, librerías y convenciones al mismo tiempo que escribe el código, todo ello sin conocer realmente el contexto del proyecto. Cada una de esas microdecisiones representa una oportunidad para generar una solución plausible, pero incorrecta para ese caso específico.&lt;/p&gt;

&lt;p&gt;El agente no alucina porque no sepa programar; alucina porque intenta completar el contexto que el desarrollador ya tiene en su cabeza, pero que nunca le fue proporcionado.&lt;/p&gt;

&lt;p&gt;Aquí es donde entra la estrategia Architect vs Typist. En lugar de delegar todas las decisiones al modelo, primero se define la arquitectura, las restricciones, las convenciones y las reglas del proyecto. Una vez acotado ese espacio de trabajo, el agente se limita a ejecutar dentro de esos límites, reduciendo drásticamente las posibilidades de alucinación y aumentando la consistencia del código generado.&lt;/p&gt;

&lt;p&gt;Typist (cómo se usa la IA normalmente):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tú: "Implementa un feature de x"
Agente: [decide estructura, elige librerías, define interfaces, escribe todo]

↑ cada decisión es una alucinación potencial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Architect (la técnica):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tú: [defines estructura, eliges librerías, defines interfaces, estableces restricciones]
Agente: [solo escribe el código dentro de ese espacio ya definido]

↑ las decisiones ya no son del agente, solo la ejecución
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imaginemos una arquitectura de agentes con un flujo como Orchestrator → Planner → Developer → Reviewer → QA Engineer. Este es un ejemplo básico, pero podría extenderse hasta simular un equipo completo de IT compuesto por múltiples subagentes.&lt;/p&gt;

&lt;p&gt;El problema aparece cuando el Planner comienza a tomar decisiones de arquitectura sin conocer qué patrones utiliza el proyecto, qué librerías ya están instaladas, cuáles son las convenciones de la codebase o qué trade-offs son aceptables. Todo aquello que el Planner desconoce lo completa con "lo más probable", y eso es, precisamente, una alucinación en el contexto del desarrollo de software.&lt;/p&gt;

&lt;p&gt;Este problema se hace aún más evidente en escenarios como integrar un nuevo servidor MCP al flujo de trabajo (el agente asume una estructura inexistente), refactorizar un módulo (inventa dependencias que cree que deberían existir) o implementar una funcionalidad que involucra varios subagentes, donde cada uno toma microdecisiones distintas y termina generando inconsistencias.&lt;/p&gt;

&lt;p&gt;La diferencia no está en cuánto código escribe el agente, sino en quién toma las decisiones de diseño.&lt;/p&gt;

&lt;p&gt;Una estrategia eficaz para mitigar este tipo de alucinaciones es definir un Architecture Decision Record (ADR) antes de solicitar la implementación al Planner o al subagente responsable de las decisiones arquitectónicas. De esta forma, las decisiones críticas dejan de ser suposiciones del modelo y pasan a ser restricciones explícitas que todos los agentes deben seguir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## DECISIÓN ARQUITECTÓNICA — [nombre del componente]&lt;/span&gt;

&lt;span class="gu"&gt;### Qué construir&lt;/span&gt;
[una sola oración, sin ambigüedad]

&lt;span class="gu"&gt;### Archivos involucrados&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Crear: .opencode/proxy/index.js
&lt;span class="p"&gt;-&lt;/span&gt; Crear: .opencode/proxy/targets.js
&lt;span class="p"&gt;-&lt;/span&gt; Crear: .opencode/proxy/semantic.js
&lt;span class="p"&gt;-&lt;/span&gt; NO tocar: opencode.json (solo se muestra como referencia)

&lt;span class="gu"&gt;### Stack y librerías&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Runtime: Node.js ESM (type: module en package.json)
&lt;span class="p"&gt;-&lt;/span&gt; MCP SDK: @modelcontextprotocol/sdk ^1.0.0 — usar StdioServerTransport
&lt;span class="p"&gt;-&lt;/span&gt; Embeddings: @xenova/transformers — modelo Xenova/all-MiniLM-L6-v2
&lt;span class="p"&gt;-&lt;/span&gt; NO usar: langchain, openai SDK, ni ninguna otra dependencia

&lt;span class="gu"&gt;### Interfaces y contratos&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; El proxy recibe --target=&lt;span class="nt"&gt;&amp;lt;nombre&amp;gt;&lt;/span&gt; como arg CLI
&lt;span class="p"&gt;-&lt;/span&gt; Expone tools/list y tools/call únicamente
&lt;span class="p"&gt;-&lt;/span&gt; tools/list devuelve máximo TOP_K tools (default 8, configurable por env PROXY_TOP_K)
&lt;span class="p"&gt;-&lt;/span&gt; tools/call hace forward directo sin modificar params ni resultado

&lt;span class="gu"&gt;### Restricciones explícitas&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Sin estado en memoria entre sesiones (cache solo en cache.json en disco)
&lt;span class="p"&gt;-&lt;/span&gt; Sin servidor HTTP — solo stdio transport
&lt;span class="p"&gt;-&lt;/span&gt; Auth: leer token desde ~/.local/share/opencode/mcp-auth.json, fallback a env var
&lt;span class="p"&gt;-&lt;/span&gt; Si el archivo de tokens no existe o el token es null → lanzar error descriptivo, NO silenciar

&lt;span class="gu"&gt;### Lo que NO debe decidir el agente&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Estructura de carpetas (ya definida arriba)
&lt;span class="p"&gt;-&lt;/span&gt; Qué librería de embeddings usar (ya definida)
&lt;span class="p"&gt;-&lt;/span&gt; Cómo manejar errores de auth (ya definido)
&lt;span class="p"&gt;-&lt;/span&gt; El valor por defecto de TOP_K (es 8)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consideración&lt;br&gt;
Esta plantilla es solo un ejemplo. Muchas de sus secciones pueden omitirse si se aprovechan correctamente archivos como AGENTS.md, donde es posible definir la arquitectura, el stack tecnológico, las convenciones del proyecto y otras restricciones globales. Del mismo modo, parte de este contexto puede vivir en el system prompt del Orchestrator o de los subagentes encargados de las decisiones arquitectónicas, como el Planner o el Spec Manager.&lt;/p&gt;

&lt;p&gt;Cuando el Orchestrator recibe este contexto, prácticamente no hay nada que "adivinar": las decisiones de diseño ya están tomadas. El Developer simplemente traduce la especificación a código. Cabe aclarar que el ADR puede haber sido escrito previamente por el equipo o generarse automáticamente por el Spec Manager, como se verá más adelante.&lt;/p&gt;

&lt;p&gt;El segundo gran ajuste para que esta estrategia funcione correctamente es modificar los system prompts de los subagentes. En este caso, se ajustará el Spec Manager, el agente especializado en la creación de changes con OpenSpec siguiendo la metodología SDD.&lt;/p&gt;

&lt;p&gt;El cambio clave consiste en añadir un gate de decisión arquitectónica dentro de su system prompt. Este mecanismo determinará si es necesario crear un ADR antes de generar el change. La decisión dependerá de si el plan afecta algún aspecto arquitectónicamente significativo del proyecto.&lt;/p&gt;

&lt;p&gt;La guía AWS &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/architectural-decision-records/adr-process.html" rel="noopener noreferrer"&gt;Prescriptive Guidance&lt;/a&gt; establece uno de los criterios más utilizados en la industria: se debe crear un ADR por cada decisión arquitectónicamente significativa que impacte el proyecto, ya sea en su estructura (por ejemplo, la adopción de un patrón como microservicios) o en requisitos no funcionales como seguridad, alta disponibilidad o tolerancia a fallos. Si el cambio no afecta ninguno de estos aspectos, el Spec Manager puede generar el change sin necesidad de crear un ADR.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnc03ll44otbvx4m37d8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnc03ll44otbvx4m37d8a.png" alt="spec-manager command slash" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora aplicaremos una técnica de prompt engineering conocida como one-shot/few-shot prompting. Esta consiste en proporcionar ejemplos dentro del system prompt; en este caso, al Spec Manager, para guiar su comportamiento y reducir la ambigüedad en la toma de decisiones.&lt;/p&gt;

&lt;p&gt;A partir de este punto, continuaremos ajustando los artefactos generados por el agente, tanto el Architecture Decision Record (ADR) como los artefactos de OpenSpec, con el objetivo de que sean más consistentes, precisos y alineados con la arquitectura del proyecto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffo9wkcto6bep988etwbz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffo9wkcto6bep988etwbz.png" alt="spec-manager one shot" width="800" height="945"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con esta técnica se le muestra al modelo un ejemplo concreto de entrada → salida esperada para un patrón específico, en lugar de limitarse a describir la regla de forma abstracta (por ejemplo, "ejecuta el comando delegado tal cual"). A partir de ese ejemplo, el modelo generaliza el comportamiento y lo aplica a comandos similares que no estaban presentes en el prompt, reduciendo la ambigüedad y aumentando la consistencia de sus respuestas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1msvo8il785xrcvw2rd3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1msvo8il785xrcvw2rd3.png" alt="generate artifacts" width="800" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora continuaremos con el contenido del comando /opsx-adr, el cual sigue la metodología Command Driven Development (CDD) y extiende el conjunto de comandos proporcionados por OpenSpec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;---&lt;/span&gt;
description: Create an Architecture Decision Record &lt;span class="o"&gt;(&lt;/span&gt;ADR&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;an existing change, capturing a significant architectural decision
&lt;span class="nt"&gt;---&lt;/span&gt;

Create an Architecture Decision Record &lt;span class="o"&gt;(&lt;/span&gt;ADR&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;a change that has already been explored and proposed.

I&lt;span class="s1"&gt;'ll create an ADR that:
- documents the decision made, the alternatives considered, and its consequences
- lives outside the change folder so it persists after the change is archived
- stays in `Proposed` status until @reviewer accepts it during `/opsx-verify`

This command does not decide whether an ADR is needed — that decision is made by @orchestrator or @planner before this command is delegated. `/opsx-adr` only executes the creation.

---

**Input**: The argument after `/opsx-adr` is the change name (kebab-case) this decision belongs to. Optionally, `--supersedes &amp;lt;adr-id&amp;gt;` if this decision replaces a previously accepted ADR.

**Steps**

1. **If no input provided, ask which change this ADR belongs to**

   Use the **AskUserQuestion tool** (open-ended, no preset options) to ask:
   &amp;gt; "Which change is this architectural decision for? Provide the change name."

   **IMPORTANT**: Do NOT proceed without a valid, existing change name — an ADR cannot be created standalone, only against an already-explored change.

2. **Verify the change has enough context to justify an ADR**
   openspec status --change "&amp;lt;name&amp;gt;" --json

   Confirm the `proposal` and `design` artifacts both show `status: "done"`. If either is missing or pending, halt and report:
   &amp;gt; "ADR requires a completed design before it can be created — run /opsx-propose first."

3. **Confirm the schema supports ADRs**

   Parse the `artifacts` array from step 2. If `adr` is not listed, halt and report:
   &amp;gt; "This project'&lt;/span&gt;s schema doesn&lt;span class="s1"&gt;'t define an ADR artifact. Switch to the spec-driven-with-adr schema in openspec/config.yaml."

4. **Get ADR instructions**
   openspec instructions adr --change "&amp;lt;name&amp;gt;" --json

   Parse:
   - `context`, `rules`: constraints for you (never copied into the output file)
   - `template`: structure to use for the ADR
   - `instruction`: schema-specific guidance for this artifact type
   - `outputPath`: where to write it (outside `changes/`, under `openspec/adr/`)
   - `dependencies`: `proposal.md` and `design.md` — read these for context before writing

5. **If `--supersedes &amp;lt;adr-id&amp;gt;` was provided**
   - Read the referenced prior ADR at its existing path for context
   - Reference it in the new ADR'&lt;/span&gt;s &lt;span class="s2"&gt;"Supersedes"&lt;/span&gt; section
   - Do NOT edit the prior ADR&lt;span class="s1"&gt;'s content or status here — the actual status change on the prior ADR happens during `/opsx-verify`, when @reviewer accepts the new one

6. **Create the ADR file**
   - Use `template` as the structure — fill in its sections
   - Ground `Context` in the problem statement from `proposal.md`
   - Ground `Decision` and `Alternatives Considered` in the approach discussion from `design.md`
   - Set `Status: Proposed`
   - Show brief progress: `"Created adr"`

7. **Show final status**
   openspec status --change "&amp;lt;name&amp;gt;"


**Output**

After creating the ADR, summarize:
- ADR file path and the change it belongs to
- Status: `Proposed`
- Prompt: "Ready for @reviewer to accept during `/opsx-verify`."

**Artifact Creation Guidelines**

- Follow the `instruction` field from `openspec instructions adr` for what the ADR should contain
- Read `proposal.md` and `design.md` before writing — the ADR is grounded in the change, never invented independently
- **IMPORTANT**: `context` and `rules` are constraints for YOU, not content for the file — never copy them into the output
- Never set `Status` to anything other than `Proposed` on creation — acceptance is a review-time decision, not a creation-time one

**Guardrails**
- Never create an ADR for a change without a completed `design.md`
- Never overwrite an existing ADR for this change without `--supersedes` — if one exists, ask the user whether to supersede it
- Never modify a prior ADR'&lt;/span&gt;s content or status when superseding — only reference it &lt;span class="k"&gt;in &lt;/span&gt;the new file
- Verify the ADR file exists after writing before reporting success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una aclaración&lt;br&gt;
Actualmente trabajo con un setup de orquestación de agentes basado en OpenCode y OpenSpec (SDD). En este punto es normal que la estrategia de los ADR pueda parecer confusa o que surjan dudas sobre cómo está construido todo el flujo.&lt;/p&gt;

&lt;p&gt;La idea de esta serie es ir presentando el setup, las configuraciones y las implementaciones de forma progresiva. Un ejemplo de ello es la extensión de OpenSpec mediante /opsx-adr, un comando que desarrollé para integrar los Architecture Decision Records (ADR), ya que no forma parte del conjunto de comandos nativos de OpenSpec.&lt;/p&gt;

&lt;p&gt;Si quieres comprender mejor cómo conviven los ADR con OpenSpec dentro de este flujo de trabajo, te recomiendo la siguiente lectura.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://intent-driven.dev/blog/2026/04/29/spec-driven-development-with-adr/" rel="noopener noreferrer"&gt;Architectural Decision Records with Spec-Driven Development using OpenSpec&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Aun implementando estas estrategias, es posible que las alucinaciones sigan apareciendo. Sin embargo, su incidencia suele ser considerablemente menor que cuando no se aplica ningún tipo de control sobre el contexto, la arquitectura o el comportamiento de los agentes.&lt;/p&gt;

&lt;p&gt;También es importante aclarar que este artículo no aborda la creación de agentes en las diferentes herramientas disponibles en el mercado. Cada plataforma tiene su propia forma de definirlos. Por ejemplo, en OpenCode basta con referenciar el archivo Markdown que contiene el system prompt del agente desde el archivo opencode.json, mientras que en Claude Code este suele ubicarse directamente en .claude/agents/agent-system-prompt.md.&lt;/p&gt;

&lt;p&gt;En las siguientes entregas se profundizará en la composición de los system prompts y en el uso de distintas técnicas de prompt engineering para redactar instrucciones más precisas y obtener agentes más consistentes.&lt;/p&gt;

&lt;p&gt;Por último, cabe aclarar que esta será una serie de artículos de carácter incremental. Muchas de las estrategias que se abordarán son relativamente avanzadas y sería difícil explicarlas con el nivel de detalle necesario en un único artículo.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>ai</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>AI Agents no son magia: cómo construí un equipo de 7 especialistas que desarrollan software sin alucinar</title>
      <dc:creator>Johan Garcia</dc:creator>
      <pubDate>Fri, 22 May 2026 00:28:26 +0000</pubDate>
      <link>https://dev.to/devjohanadrian/ai-agents-no-son-magia-como-construi-un-equipo-de-7-especialistas-que-desarrollan-software-sin-1ah6</link>
      <guid>https://dev.to/devjohanadrian/ai-agents-no-son-magia-como-construi-un-equipo-de-7-especialistas-que-desarrollan-software-sin-1ah6</guid>
      <description>&lt;p&gt;Todos probamos asistentes de código con AI. Al principio impresionan: escribes un comentario y te generan un endpoint completo. Te sentís como Tony Stark. Luego aparece la realidad. A las cinco interacciones, el agente pierde el contexto. &lt;/p&gt;

&lt;p&gt;Te importa una librería que no existe. Mezcla la lógica de autenticación con la de base de datos. &lt;/p&gt;

&lt;p&gt;Te manda un PR que no compila. Y mientras tanto, quemás tokens como si fueran infinitos. El problema no es la AI. &lt;/p&gt;

&lt;p&gt;El problema es que la tratamos como un oráculo, no como un equipo. Le pedimos que haga todo a la vez: entender el requerimiento, diseñar la arquitectura, escribir el código, revisar su propio trabajo y hacer el commit. Eso no es cómo funciona la ingeniería de software. Y tampoco es cómo debería funcionar cuando la AI está en el medio.&lt;/p&gt;




&lt;h2&gt;
  
  
  La solución un orquestador
&lt;/h2&gt;

&lt;p&gt;En vez de un solo agente que intenta hacer todo, construí un sistema con 8 agentes especializados.&lt;/p&gt;

&lt;p&gt;La arquitectura es simple: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;1 Orchestrator: el coordinador. No escribe código. No hace reviews. Solo recibe tu pedido, entiende qué se necesita, delega al subagente correcto y trackea el progreso. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;7 Subagents: cada uno con un rol acotado y bien definido. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[DIAGRAM: Diagrama mostrando Orchestrator en el centro conectado a los 7 subagentes con etiquetas de sus responsabilidades Los subagentes tienen responsabilidades que no se solapan: &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7otp3mffyi7biyx70hm.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7otp3mffyi7biyx70hm.jpeg" alt="Agents_table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cada agente sabe exactamente qué le toca y, más importante, qué NO le toca. Esto no es "poner un montón de prompts en un archivo". Es aplicar el mismo principio que usamos en backend: separación de responsabilidades.&lt;/p&gt;

&lt;p&gt;No todos los agentes usan el mismo modelo de AI. Y eso es intencional.&lt;/p&gt;

&lt;p&gt;Tareas simples: Escribir specs, revisar código, gestionar archivos —usan modelos baratos y rápidos. No necesitás un modelo de 200B de parámetros para revisar si un middleware valida un token. &lt;br&gt;
Tareas complejas implementación de features, resolución de bugs difíciles usan modelos más capaces y más caros. Ahí sí vale la pena invertir. Cada agente tiene permisos granulares definidos en su configuración: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;El developer puede escribir archivos y ejecutar comandos bash.&lt;/li&gt;
&lt;li&gt;El reviewer solo puede leer y comentar. No toca nada. &lt;/li&gt;
&lt;li&gt;El orchestrator solo puede delegar tareas a otros agentes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esto es el principio de mínimos privilegios aplicado a agentes de AI. Si un agente no necesita escribir archivos, no debería poder hacerlo. Punto. &lt;/p&gt;

&lt;p&gt;El resultado: menos superficie de error, menos alucinaciones, y costos predecibles.&lt;/p&gt;


&lt;h2&gt;
  
  
  El truco — &lt;code&gt;/grill-me&lt;/code&gt; y &lt;code&gt;/caveman&lt;/code&gt; (Skills)
&lt;/h2&gt;

&lt;p&gt;Acá es donde la cosa se pone interesante. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;/grill-me&lt;/code&gt;: la entrevista antes del código Antes de escribir cualquier spec o línea de código, el sistema te entrevista. &lt;/p&gt;

&lt;p&gt;No es un "¿qué querés hacer?" y ya. Es una conversación estructurada que recorre cada rama del árbol de decisiones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; *"¿Qué pasa si el endpoint recibe datos malformados?"* 
&amp;gt; *"¿Cómo manejamos autenticación vs autorización?"* 
&amp;gt; *"¿Cuál es el alcance exacto de este cambio?"* 
&amp;gt; *"¿Hay edge cases que no estamos viendo?"* 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El usuario debe confirmar entendimiento compartido antes de que la AI toque un solo archivo. Esto eliminó el problema #1 de los asistentes de código: hacer rápido lo incorrecto. &lt;/p&gt;

&lt;p&gt;Porque el mayor desperdicio no es que la AI sea lenta. Es que sea rápida en la dirección equivocada. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;/caveman&lt;/code&gt;: comunicación comprimida Los tokens cuestan plata. Y el tiempo del dev también. &lt;code&gt;/caveman&lt;/code&gt; es un protocolo de comunicación que reduce el uso de tokens ~75%. Elimina artículos, filler y cortesías innecesarias:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; *"Sure, I'd be happy to help you with that! Let me take a look at the authentication middleware and see what might be causing the issue..."*  

Se convierte en:  

&amp;gt; *"Fix auth middleware. Token expiry uses `&amp;lt;` not `&amp;lt;=`."*  

No es ser grosero. Es ser preciso. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Además, hay una regla de las 20 palabras: si un agente necesita más de 20 palabras para explicar un concepto recurrente, ese concepto se comprime en un &lt;strong&gt;glosario central&lt;/strong&gt; (&lt;code&gt;CONTEXT.md&lt;/code&gt;). La próxima vez, el agente solo referencia el término. El efecto compuesto es exponencial: &lt;/p&gt;

&lt;p&gt;CONTEXT injection → todos los agentes comparten el mismo vocabulario &lt;br&gt;
Regla de 20 palabras → los conceptos repetidos se comprimen &lt;br&gt;
Caveman mode → la comunicación va directo al grano Menos tokens = menos costo = más interacciones útiles antes de que el contexto se sature. &lt;/p&gt;

&lt;p&gt;Ambas skill pertenecen a &lt;a href="https://www.linkedin.com/in/mapocock/" rel="noopener noreferrer"&gt;Matt Pocock&lt;/a&gt; y aqui su repositorio → &lt;a href="https://github.com/mattpocock/skills" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tambien pueden encontrar estas skill en &lt;a href="https://www.skills.sh/" rel="noopener noreferrer"&gt;Skills.sh&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Spec-Driven Development
&lt;/h2&gt;

&lt;p&gt;Meses atrás, cuando el vibe coding estaba en auge, vi bastante claro hacia dónde iba el problema: desarrollar software sin ningún tipo de control, proceso o sistema estaba destinado a fallar tarde o temprano.&lt;/p&gt;

&lt;p&gt;Esa idea terminó de confirmarse cuando un cliente me contactó para ayudarle a arreglar el desastre que había generado utilizando este enfoque. Lo más curioso es que, hasta cierto punto, el sistema “funcionaba”, pero era completamente insostenible.&lt;/p&gt;

&lt;p&gt;La aplicación no escalaba, no existían medidas reales de seguridad, no había separación de responsabilidades ni estándares mínimos de calidad. Todo el código estaba altamente acoplado, lleno de lógica duplicada y sin buenas prácticas de desarrollo. Honestamente, me sorprendió que la aplicación siguiera funcionando; parecía hacerlo por pura inercia.&lt;/p&gt;

&lt;p&gt;Leer, entender y limpiar ese codebase fue un auténtico infierno.&lt;/p&gt;

&lt;p&gt;Y ahí es donde entra Spec Driven Development (SDD).&lt;/p&gt;

&lt;p&gt;No voy a profundizar demasiado en el tema porque no es el objetivo principal de esta entrada, pero sí considero importante mencionarlo: SDD es un enfoque de desarrollo que busca aportar coherencia, estructura y control al desarrollo de aplicaciones asistidas por AI.&lt;/p&gt;

&lt;p&gt;La idea no es únicamente generar código más rápido, sino construir sistemas mantenibles, escalables y entendibles, donde exista trazabilidad entre requerimientos, decisiones técnicas, arquitectura e implementación.&lt;/p&gt;

&lt;p&gt;Para más información, recomiendo revisar la documentación oficial de OpenSpec → &lt;a href="https://github.com/Fission-AI/OpenSpec/tree/main/docs" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;También recomiendo este artículo, que considero especialmente valioso de &lt;a href="https://www.linkedin.com/in/harikrishnan83/" rel="noopener noreferrer"&gt;Hari Krishnan&lt;/a&gt; → &lt;a href="https://intent-driven.dev/blog/2025/11/09/spec-driven-development-openspec-source-truth/" rel="noopener noreferrer"&gt;Spec-Driven Development with OpenSpec - Source of Truth Specification&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora mi modificación:&lt;/p&gt;

&lt;p&gt;La fase 0 (&lt;code&gt;/grill-me&lt;/code&gt;) asegura que el plan es correcto antes de invertir tiempo en escribirlo. Esto no es más burocracia. Es la misma disciplina que usamos en ingeniería de software escribir tests antes del código, diseñar la API antes de implementarla pero aplicada a cómo hablamos con la AI. &lt;/p&gt;

&lt;p&gt;La diferencia es que antes esa disciplina vivía en la cabeza del senior. Ahora vive en el sistema., esto se combina con la fase de exploracion de OpenSpec para generar Artefactos mas solidos &lt;/p&gt;




&lt;h2&gt;
  
  
  MCPs: los plugins del sistema
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) es el protocolo que conecta los agentes con servicios externos. Piensalo como los plugins del ecosistema: sin ellos, los agentes operan en el vacío. &lt;/p&gt;

&lt;p&gt;Dos MCPs están configurados en este sistema: &lt;/p&gt;

&lt;p&gt;Composio: Conecta con Trello para project management. El project-manager puede crear cards, moverlas entre listas y actualizar estados sin salir del terminal. El progreso del sprint queda trackeado automáticamente. &lt;br&gt;
Context7: Documentación técnica actualizada al instante. Cuando el developer implementa un endpoint con Express o define un schema con Prisma, consulta la API más reciente en lugar de confiar en su training data. Esto elimina las alucinaciones de imports y APIs deprecadas. &lt;/p&gt;

&lt;p&gt;Esto cierra el loop completo: specs escritas en archivos versionados, implementación con documentación fresca, y tracking automático en Trello. Nada queda en el aire.&lt;/p&gt;

&lt;p&gt;Algo importante a tener en cuenta al utilizar el protocolo MCP dentro de arquitecturas basadas en agentes es que las tools registradas por cada MCP se cargan directamente en el contexto del modelo. Esto puede generar conflictos o ejecuciones no deseadas de comandos entre agentes, especialmente en arquitecturas con múltiples responsabilidades y acceso compartido a herramientas.&lt;/p&gt;

&lt;p&gt;Para evitar este tipo de problemas, es recomendable restringir qué agentes pueden acceder a determinados MCPs. Esto puede controlarse desde la configuración de opencode.json o directamente desde el system prompt de cada agente, definiendo explícitamente sus capacidades, límites y herramientas disponibles.&lt;/p&gt;

&lt;p&gt;Comparto tanto la configuración de la arquitectura en OpenCode como los system prompts de cada uno de los agentes. Toda esta información está en inglés, ya que los modelos suelen ofrecer mejores resultados cuando trabajan en el idioma principal con el que fueron entrenados.&lt;/p&gt;

&lt;p&gt;No adjunto archivos como CONTEXT.md ni AGENTS.md / CLAUDE.md. El primero funciona principalmente como un diccionario compartido para estandarizar el lenguaje entre agentes y ayudar a reducir el consumo de tokens ligado a /caveman. El segundo corresponde a archivos de configuración y contexto operativo del sistema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuración de opencode&lt;/strong&gt; → &lt;a href="https://gist.github.com/DevJohanAdrian/5d489ec5adf75fd15d0053bce41cd870" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System Prompts de cada unos de los agentes&lt;/strong&gt; → &lt;a href="https://gist.github.com/DevJohanAdrian/649f4662bf578333ed457bc887faee96" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;La arquitectura implementa un enfoque híbrido combinando Intent Driven Development y Command Driven Development.&lt;/p&gt;

&lt;p&gt;La fase inicial comienza con /grill-me, considerada como la fase 0 del flujo. En esta etapa, el orquestador es responsable de realizar la entrevista, validar requerimientos y consolidar el contexto funcional y técnico del problema esto es Intent Driven.&lt;/p&gt;

&lt;p&gt;Una vez los requerimientos son suficientemente sólidos y consistentes, el subagente spec-manager entra en acción para encargarse de la creación de los artefactos de OpenSpec y estructurar formalmente las especificaciones del proyecto y aqui empezamos a hacer Command Driven.&lt;/p&gt;

&lt;p&gt;Otros apartados que no mencioné anteriormente, pero que también forman parte importante de esta arquitectura, son los procesos de automatización alrededor del ciclo de integración y gestión operativa del proyecto.&lt;/p&gt;

&lt;p&gt;Uno de ellos fue la automatización completa del flujo de integración de código en GitHub mediante slash commands. Todo el ciclo puede ejecutarse desde la terminal: generación de commits, estandarización de mensajes, validaciones y procesos de push, reduciendo fricción operativa y manteniendo consistencia dentro del flujo de trabajo.&lt;/p&gt;

&lt;p&gt;Otro enfoque que también terminó formando parte de la arquitectura fue la automatización de gestión en Trello bajo un modelo Command Driven. Esto permitió administrar tarjetas, estados y operaciones del tablero directamente desde la TUI (Terminal User Interface) utilizando slash commands.&lt;/p&gt;

&lt;p&gt;La idea detrás de este enfoque no era únicamente automatizar tareas repetitivas, sino convertir la terminal en un centro operativo unificado donde los agentes, comandos y flujos de trabajo convivieran dentro de un mismo ecosistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nota final
&lt;/h2&gt;

&lt;p&gt;Este enfoque aún se encuentra en una etapa de maduración, pero ya cuenta con una base sólida y funcional. A futuro, la idea es incorporar memoria persistente mediante herramientas como &lt;a href="https://github.com/Gentleman-Programming/engram" rel="noopener noreferrer"&gt;Engram&lt;/a&gt;, además de continuar refinando la arquitectura hasta convertirla en una solución mucho más robusta y profesional.&lt;/p&gt;

&lt;p&gt;Actualmente, gran parte del trabajo está centrado en laboratorios y pruebas experimentales alrededor de skills, MCPs, técnicas de orquestación y distintos enfoques de desarrollo con agentes.&lt;/p&gt;

&lt;p&gt;Toda esta base también está respaldada por experiencia práctica acumulada durante aproximadamente 7 años trabajando en desarrollo de software, arquitectura y resolución de problemas reales.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Camino a CI/CD pruebas (Testing)</title>
      <dc:creator>Johan Garcia</dc:creator>
      <pubDate>Fri, 10 Apr 2026 05:09:40 +0000</pubDate>
      <link>https://dev.to/devjohanadrian/camino-a-cicd-pruebas-testing-3ohn</link>
      <guid>https://dev.to/devjohanadrian/camino-a-cicd-pruebas-testing-3ohn</guid>
      <description>&lt;p&gt;El stage de testing es, en la mayoría de pipelines, la etapa que sigue después de la compilación o build. En este punto, el sistema ya es ejecutable, pero aún no es confiable.&lt;/p&gt;

&lt;p&gt;Aquí es donde entra el testing: no como un paso opcional, sino como el filtro que evita que errores, regresiones o comportamientos inesperados lleguen a producción.&lt;/p&gt;

&lt;p&gt;En esta sección, se busca responder una pregunta clave:&lt;/p&gt;

&lt;p&gt;¿Qué debería tener un pipeline a nivel de testing para considerarse realmente sólido?&lt;/p&gt;




&lt;h2&gt;
  
  
  Tipos de Testing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Testing Funcional&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El testing funcional valida que el sistema haga lo que se espera que haga. Es decir, se enfoca en el comportamiento, no en cómo está implementado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unit Testing (Pruebas Unitarias)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Las pruebas unitarias validan las piezas más pequeñas del sistema: funciones, métodos o componentes individuales.&lt;/p&gt;

&lt;p&gt;Su objetivo es detectar errores lo más temprano posible, antes de que escalen.&lt;/p&gt;

&lt;p&gt;Qué cubren normalmente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lógica de negocio aislada&lt;/li&gt;
&lt;li&gt;Validaciones&lt;/li&gt;
&lt;li&gt;Transformaciones de datos&lt;/li&gt;
&lt;li&gt;Casos borde&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaalrornlbg0c5btc7uh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaalrornlbg0c5btc7uh.png" alt=" " width="800" height="1140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí no importa el sistema completo, solo que esa unidad funcione correctamente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbbcvd9naupvf0n5ia30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbbcvd9naupvf0n5ia30.png" alt=" " width="800" height="791"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integration Testing (Pruebas de Integración)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Aquí se sube un nivel: ya no se prueba una pieza aislada, sino cómo interactúan varias partes del sistema.&lt;/p&gt;

&lt;p&gt;El objetivo es validar que los componentes colaboren correctamente.&lt;/p&gt;

&lt;p&gt;Qué suele incluir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Componentes + servicios&lt;/li&gt;
&lt;li&gt;Acceso a base de datos&lt;/li&gt;
&lt;li&gt;APIs simuladas (MSW, mocks controlados)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ejemplo conceptual:&lt;/p&gt;

&lt;p&gt;Un componente llama a un servicio → el servicio consulta datos → el resultado se renderiza correctamente.&lt;/p&gt;

&lt;p&gt;Si alguna de esas piezas falla en conjunto, el test lo detecta.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1dwn9ovgsqodq9rgxtny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1dwn9ovgsqodq9rgxtny.png" alt=" " width="800" height="1105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcvrq4fhtwbd76hgft25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcvrq4fhtwbd76hgft25.png" alt=" " width="800" height="1385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;End-to-End Testing (E2E)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Las pruebas E2E validan el sistema completo desde la perspectiva del usuario.&lt;/p&gt;

&lt;p&gt;Simulan flujos reales en un entorno lo más cercano posible a producción.&lt;/p&gt;

&lt;p&gt;Ejemplo típico:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El usuario entra a la app&lt;/li&gt;
&lt;li&gt;Hace login&lt;/li&gt;
&lt;li&gt;Crea un registro&lt;/li&gt;
&lt;li&gt;Lo visualiza en pantalla&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si todo eso funciona, el sistema cumple su propósito en ese flujo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv39e5qhlfqw86ipjs9eh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv39e5qhlfqw86ipjs9eh.png" alt=" " width="800" height="1487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smoke Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El smoke testing responde una única pregunta:&lt;/p&gt;

&lt;p&gt;¿El sistema funciona lo suficiente como para seguir probándolo?&lt;/p&gt;

&lt;p&gt;Se ejecuta justo después del build, y actúa como un primer filtro.&lt;/p&gt;

&lt;p&gt;Si falla aquí, no tiene sentido continuar.&lt;/p&gt;

&lt;p&gt;Ejemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;¿La app levanta?&lt;/li&gt;
&lt;li&gt;¿El login responde?&lt;/li&gt;
&lt;li&gt;¿una ruta principal carga?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No valida lógica profunda ni reglas complejas.&lt;/p&gt;

&lt;p&gt;Solo verifica lo esencial.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9297woq920oeh8g320xy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9297woq920oeh8g320xy.png" alt=" " width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este test no valida:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;expiración del token&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;roles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;seguridad avanzada&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solo valida algo clave: “¿el login funciona?”,  Si esto falla, todo lo demás deja de tener sentido.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El sanity testing es un chequeo rápido y enfocado después de un cambio puntual.&lt;/p&gt;

&lt;p&gt;No busca validar todo el sistema, sino algo muy concreto:&lt;/p&gt;

&lt;p&gt;¿Lo que se modificó sigue funcionando sin romper lo demás?&lt;/p&gt;

&lt;p&gt;Se usa cuando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hay un bug fix&lt;/li&gt;
&lt;li&gt;Se hace un refactor pequeño&lt;/li&gt;
&lt;li&gt;Se ajusta una funcionalidad específica&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Características:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dirigido (no exploratorio)&lt;/li&gt;
&lt;li&gt;Ligero (no exhaustivo)&lt;/li&gt;
&lt;li&gt;Rápido (busca confianza inmediata)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdgfluh0az925gttpchsg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdgfluh0az925gttpchsg.png" alt=" " width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regression Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El regression testing protege el sistema a medida que evoluciona.&lt;/p&gt;

&lt;p&gt;Cada cambio introduce riesgo, y este tipo de pruebas actúa como una red de seguridad.&lt;/p&gt;

&lt;p&gt;Valida que:&lt;/p&gt;

&lt;p&gt;Lo que funcionaba → siga funcionando&lt;br&gt;
Los cambios → no generen efectos colaterales&lt;/p&gt;

&lt;p&gt;No se enfoca en lo nuevo, sino en evitar que lo existente se rompa.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fulr4s0aycf25l5w7cayu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fulr4s0aycf25l5w7cayu.png" alt=" " width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User Acceptance Testing (UAT)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Es la fase donde el sistema deja de evaluarse como “código que funciona” y pasa a validarse como “producto que resuelve un problema real”. Aquí ya no importa tanto si la lógica interna está bien implementada, sino si lo que se construyó realmente cumple con lo que el usuario o el negocio esperaba.&lt;/p&gt;

&lt;p&gt;En otras palabras, es el momento en el que alguien del lado del negocio no necesariamente un desarrollador usa la aplicación en escenarios reales y responde una pregunta clave: ¿esto sirve para lo que se necesitaba?&lt;/p&gt;

&lt;p&gt;A diferencia de otros tipos de testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;No se centra en funciones aisladas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No valida detalles técnicos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No busca bugs “técnicos” principalmente.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se enfoca en algo mucho más importante:&lt;/p&gt;

&lt;p&gt;Validar que el sistema cumple con los requisitos funcionales desde la perspectiva del usuario final.&lt;/p&gt;

&lt;p&gt;Ejemplo&lt;/p&gt;

&lt;p&gt;Contexto: Un módulo de inventario.&lt;/p&gt;

&lt;p&gt;Requisito de negocio:&lt;br&gt;
“El usuario debe poder registrar un producto y verlo reflejado en el inventario.”&lt;/p&gt;

&lt;p&gt;UAT:&lt;br&gt;
Escenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El usuario crea un producto: Nombre: “Laptop” Cantidad: 5&lt;/li&gt;
&lt;li&gt;Guarda el registro&lt;/li&gt;
&lt;li&gt;Va al listado de inventario&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Resultado esperado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El producto aparece&lt;/li&gt;
&lt;li&gt;La cantidad es correcta&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No hay inconsistencias&lt;/p&gt;

&lt;p&gt;Si eso pasa, el sistema cumple el requisito, aunque internamente pueda tener mejoras técnicas pendientes.&lt;/p&gt;

&lt;p&gt;Tipos de UAT que suelen aparecer&lt;br&gt;
Aunque muchas veces se agrupan como uno solo, en la práctica se ven variantes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alpha Testing → interno (equipo del producto)&lt;/li&gt;
&lt;li&gt;Beta Testing → usuarios reales&lt;/li&gt;
&lt;li&gt;Business UAT → validación contra requisitos del negocio&lt;/li&gt;
&lt;li&gt;Operational UAT → validación en condiciones reales (ambiente, datos, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consideraciones &lt;/p&gt;

&lt;p&gt;El UAT no lo hace el desarrollador&lt;/p&gt;

&lt;p&gt;Normalmente lo ejecutan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Stakeholders&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;QA con enfoque de negocio&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cliente final&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Porque lo que se valida no es el código, sino la utilidad real del sistema.&lt;/p&gt;

&lt;p&gt;Su finalidad es&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ejecutarse en entornos de staging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ser parcialmente manual (aunque puede automatizarse con criterios de aceptación)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Actuar como último gate antes de producción&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Contract Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Este tipo de testing se vuelve crítico en arquitecturas distribuidas.&lt;/p&gt;

&lt;p&gt;Valida que dos sistemas que se comunican (por ejemplo, frontend y backend) respeten un contrato.&lt;/p&gt;

&lt;p&gt;Ese contrato define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request&lt;/li&gt;
&lt;li&gt;Response&lt;/li&gt;
&lt;li&gt;Tipos de datos&lt;/li&gt;
&lt;li&gt;Campos obligatorios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Problema típico que resuelve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;El backend funciona, sus tests pasan… pero el frontend se rompe.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El contract testing evita ese tipo de desalineaciones.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysurvetl2txvtytsued0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysurvetl2txvtytsued0.png" alt=" " width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;El backend funciona &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Los tests del backend pasan &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pero el frontend se rompe &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aquí es donde el Contract Testing evita el desastre.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tipos de Contract Testing&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Consumer-Driven Contract Testing (el más usado)&lt;/strong&gt;&lt;br&gt;
El consumidor (frontend) define lo que necesita.&lt;/p&gt;

&lt;p&gt;Ejemplo&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7v6fxmbrb19vk5rxcc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7v6fxmbrb19vk5rxcc5.png" alt=" " width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider Verification&lt;/strong&gt;&lt;br&gt;
El backend valida que cumple ese contrato.&lt;/p&gt;

&lt;p&gt;Ejemplo&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuk1zrki9igdi9ynx71u6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuk1zrki9igdi9ynx71u6.png" alt=" " width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2. Testing No Funcional&lt;/strong&gt;&lt;br&gt;
Aquí no se valida qué hace el sistema, sino cómo se comporta.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance Testing&lt;/strong&gt;&lt;br&gt;
Se centra en evaluar cómo se comporta una aplicación bajo distintas condiciones de carga, no desde la lógica funcional, sino desde atributos como tiempo de respuesta, throughput, uso de recursos y estabilidad. En términos prácticos, lo que se busca es responder preguntas como: ¿cuántos usuarios simultáneos puede soportar el sistema?, ¿qué tan rápido responde bajo presión?, ¿en qué punto comienza a degradarse? Este tipo de pruebas es clave en sistemas reales porque muchos fallos no aparecen en desarrollo, sino cuando el sistema enfrenta tráfico real. Dentro de este enfoque se incluyen variantes como load testing, stress testing y spike testing, cada una orientada a distintos patrones de carga.&lt;/p&gt;

&lt;p&gt;Ejemplo &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjv6bjmz9vmk0hhgjin0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjv6bjmz9vmk0hhgjin0v.png" alt=" " width="800" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El el ejemplo anterior se simulan 50 usuarios concurrentes durante 30 segundos haciendo peticiones al mismo endpoint. Si el sistema responde rápido y sin errores, el comportamiento es aceptable. Si el tiempo de respuesta aumenta significativamente o aparecen errores (timeouts, 500), entonces ya se está evidenciando un problema de rendimiento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Testing&lt;/strong&gt;&lt;br&gt;
Aunque forma parte del testing, muchas veces se maneja como un stage independiente.&lt;/p&gt;

&lt;p&gt;Incluye:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;SAST - Static Application Security Testing (análisis estático)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DAST - Dynamic Application Security Testing (análisis dinámico)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SCA - Software Composition Analysis&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Secrets Detection&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Container Security&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;IaC, API, y Compliance &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security Headers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dependency Scanning&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mutation Testing (Pruebas de Mutación)&lt;/strong&gt;&lt;br&gt;
El mutation testing pregunta: "Si introduzco un pequeño bug en mi código, ¿mis pruebas realmente lo detectarán?" Esto revela la diferencia crítica entre cobertura de pruebas y efectividad de pruebas. &lt;/p&gt;

&lt;p&gt;El resultado se mide con el mutation score.&lt;/p&gt;

&lt;p&gt;Ejemplo&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm200awuipzk35zebo1mi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm200awuipzk35zebo1mi.png" alt=" " width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Herramientas
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Testing Unitario e Integración&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jest (JavaScript/TypeScript)&lt;/li&gt;
&lt;li&gt;Pytest (Python):&lt;/li&gt;
&lt;li&gt;JUnit (Java)&lt;/li&gt;
&lt;li&gt;NUnit (C#/.NET)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Testing E2E y UI&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selenium: Arquitectura empresarial de Selenium Python con Pytest, Allure y patrones de diseño GitHub&lt;/li&gt;
&lt;li&gt;Cypress&lt;/li&gt;
&lt;li&gt;Playwright&lt;/li&gt;
&lt;li&gt;Puppeteer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Contract Testing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pact: Flujo típico con Pact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El frontend define el contrato&lt;/li&gt;
&lt;li&gt;Se guarda como archivo (.json)&lt;/li&gt;
&lt;li&gt;El backend ejecuta tests contra ese contrato
Si algo no coincide → falla el pipeline&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Testing Performance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Locust (Python)&lt;/li&gt;
&lt;li&gt;K6 (JavaScript/TS): Ofrece integración nativa con CI/CD y la nube.&lt;/li&gt;
&lt;li&gt;Gatling (Java/Kotlin/JS/Scala)&lt;/li&gt;
&lt;li&gt;Apache JMeter Java/GUI): Ideal para equipos QA tradicionales y empresas, siendo opensource.&lt;/li&gt;
&lt;li&gt;Atillery (Node.js/YAML)&lt;/li&gt;
&lt;li&gt;Vegeta (Go)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Alternativas en la nube para Testing performance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BlazeMeter: Permite ejecutar scripts de JMeter, k6, Locust y Gatling en la nube&lt;/li&gt;
&lt;li&gt;LoadNinja: Se enfoca en pruebas con navegadores reales en lugar de simular protocolos, lo que da métricas de experiencia de usuario más precisas. No requiere programación&lt;/li&gt;
&lt;li&gt;Azure Load Testing: Un servicio gestionado por Microsoft que permite subir scripts de JMeter y ofrece integraciones profundas con el ecosistema de Azure.&lt;/li&gt;
&lt;li&gt;OctoPerf: Diseñado específicamente para usuarios de JMeter que quieren una interfaz web moderna&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Testing Mutation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PIT (PITest) para Java con escalabilidad empresarial.&lt;/li&gt;
&lt;li&gt;Stryker Mutator con soporte multi-lenguaje (JavaScript, TypeScript, C#, Scala).&lt;/li&gt;
&lt;li&gt;MutPy para Python. &lt;/li&gt;
&lt;li&gt;Infection para PHP.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Un buen stage de testing no se define por la cantidad de herramientas o tests, sino por su capacidad de generar confianza.&lt;/p&gt;

&lt;p&gt;Al final, todo se resume en esto:&lt;/p&gt;

&lt;p&gt;Detectar errores lo antes posible, con el menor costo posible, y antes de que impacten al usuario.&lt;/p&gt;

&lt;p&gt;Si el pipeline logra eso, entonces está bien diseñado.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cicd</category>
      <category>testing</category>
      <category>programming</category>
    </item>
    <item>
      <title>Como potenciar tu VS Code con Continue.dev Cline</title>
      <dc:creator>Johan Garcia</dc:creator>
      <pubDate>Fri, 25 Apr 2025 05:36:10 +0000</pubDate>
      <link>https://dev.to/devjohanadrian/como-potenciar-tu-vs-code-con-continuedev-cline-lic</link>
      <guid>https://dev.to/devjohanadrian/como-potenciar-tu-vs-code-con-continuedev-cline-lic</guid>
      <description>&lt;p&gt;Hoy en día, vemos la inteligencia artificial (IA) en todas partes, y no es de extrañar que, en el mundo del desarrollo de software, se estén explorando una gran variedad de usos. Un claro ejemplo son los editores de código con integración de IA, como Cursor.ai, Windsurf o el más reciente Firebase Studio. Estas herramientas ofrecen funcionalidades avanzadas, como autocompletado inteligente y generación o edición de código a partir de prompts.&lt;/p&gt;

&lt;p&gt;Hace unas semanas estuve probando tanto Cursor como Windsurf en algunos de mis proyectos personales, y, sinceramente, es increíble lo que se puede lograr cuando sabes bien lo que estás haciendo. Investigando un poco más, encontré una forma de darle “músculo” a Visual Studio Code —recordemos que Cursor y Windsurf están basados en VS Code—, ya que este, por defecto, no incluye muchas de las características que sí ofrecen estas versiones modificadas de pago.&lt;/p&gt;

&lt;h2&gt;
  
  
  La solución: integrar Continue.dev y Cline, dos extensiones poderosas y open source para VS Code, que transforman tu editor en un verdadero IDE con esteroides. En este artículo te voy a mostrar cómo configurarlas paso a paso, qué modelos puedes usar, sus limitaciones y por qué esta combinación puede convertirse en tu nuevo entorno favorito para programar con IA.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;REQUISITOS PREVIOS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tener Visual Studio Code instalado.&lt;/li&gt;
&lt;li&gt;Contar con una cuenta gratuita en Groq y OpenRouter.&lt;/li&gt;
&lt;li&gt;En el apartado de extensiones de VS Code, buscar la extensión Continue y asegurarte de seleccionar al desarrollador: Continue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Al instalarla, se creará una carpeta llamada .continue/ en la raíz de tu espacio de trabajo, que suele ubicarse en C:\Users\user. (Es importante tener presente este punto)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Luego, en el mismo apartado de extensiones de VS Code, buscar la extensión Cline y seleccionar al desarrollador: Cline.bot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Existen otros proveedores de modelos de IA, como Together AI, pero, al parecer, este no ofrece modelos open source.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Cómo funciona Continue.dev?&lt;/strong&gt;&lt;br&gt;
Continue.dev actúa como un asistente inteligente dentro de Visual Studio Code. Sus principales funciones incluyen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leer y analizar tu código fuente.&lt;/li&gt;
&lt;li&gt;Completar funciones o bloques de código completos.&lt;/li&gt;
&lt;li&gt;Editar fragmentos mediante prompts.&lt;/li&gt;
&lt;li&gt;Responder preguntas técnicas o sugerir mejoras.&lt;/li&gt;
&lt;li&gt;Leer el contexto del proyecto (archivos, terminal, errores, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Está especialmente orientado a desarrolladores que desean integrar modelos de lenguaje (LLMs) para mejorar su flujo de trabajo, particularmente en proyectos de tamaño mediano a grande.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Cómo funciona Cline?&lt;/strong&gt;&lt;br&gt;
Cline es un complemento para VS Code que permite crear un agente personalizado impulsado por LLMs, capaz de ejecutar comandos, navegar entre archivos y mantener conversaciones contextuales. A diferencia de Continue.dev —que se enfoca principalmente en la edición y el completado de código—, Cline está orientado a establecer un flujo de trabajo interactivo bajo un enfoque agente-usuario.&lt;/p&gt;

&lt;p&gt;Con Cline puedes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chatear con un agente inteligente directamente desde el editor.&lt;/li&gt;
&lt;li&gt;Ejecutar tareas específicas mediante comandos configurables.&lt;/li&gt;
&lt;li&gt;Definir skills (habilidades) que combinan instrucciones con ejecución de código.&lt;/li&gt;
&lt;li&gt;Personalizar completamente el comportamiento del agente mediante archivos YAML.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Está pensado para usuarios avanzados que buscan automatizar flujos repetitivos o construir asistentes que no solo respondan con texto, sino que también ejecuten acciones dentro del entorno de desarrollo.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Archivo config.yaml: explicación completa&lt;/strong&gt;&lt;br&gt;
El archivo .continue/config.yaml es el núcleo de la configuración de Continue.dev. A través de este archivo puedes definir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Los modelos a utilizar: como Groq, OpenRouter u otros compatibles con Continue.&lt;/li&gt;
&lt;li&gt;El comportamiento de cada modelo: incluyendo roles, mensajes del sistema, temperatura, y otras configuraciones específicas que controlan cómo responde el modelo.&lt;/li&gt;
&lt;li&gt;El contexto que tendrá el agente: qué archivos, errores o entradas del terminal podrá leer para generar respuestas más precisas y útiles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ejemplo con Groq y OpenRouter:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipncfrr7l2dgtft4hanc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipncfrr7l2dgtft4hanc.png" alt="Config.yaml" width="800" height="772"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicación de propiedades clave del archivo config.yaml&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name: Nombre visible del asistente o modelo en la interfaz de Continue.&lt;/li&gt;
&lt;li&gt;provider: Proveedor del modelo, como groq, openrouter, entre otros.&lt;/li&gt;
&lt;li&gt;model: Identificador del modelo específico ofrecido por el proveedor.&lt;/li&gt;
&lt;li&gt;apiKey: Clave de autenticación necesaria para conectarse con el proveedor.&lt;/li&gt;
&lt;li&gt;roles: Define las funciones que puede desempeñar el modelo, como chat, autocomplete o edit.&lt;/li&gt;
&lt;li&gt;systemMessage: Mensaje base que establece el comportamiento general del asistente (por ejemplo, su tono, propósito o enfoque).&lt;/li&gt;
&lt;li&gt;context: Determina qué fuentes de información se usarán como contexto, como archivos de código, terminal, errores, etc.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;apiBase: Dirección base para la conexión con la API, necesaria en algunos proveedores como Groq.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limitaciones de Continue.dev&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No todos los modelos soportan todas las funciones. Por ejemplo, algunos modelos no permiten funciones como edición (edit) o autocompletado (autocomplete). En estos casos, Continue mostrará una alerta indicando qué modelo y qué rol no son compatibles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No permite entrenamiento ni afinado de modelos desde la interfaz.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Algunas integraciones pueden requerir configuración manual (por ejemplo, definir rutas o parámetros específicos).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Depende en gran medida del modelo seleccionado: si el modelo es limitado, la calidad de las respuestas también lo será.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitaciones de los modelos: Groq vs OpenRouter&lt;br&gt;
Groq&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Totalmente gratuito y sin necesidad de tarjeta de crédito.&lt;/li&gt;
&lt;li&gt;Modelos disponibles: LLaMA 3, Mixtral, Gemma.&lt;/li&gt;
&lt;li&gt;Ofrece alta velocidad de respuesta, ideal para flujos interactivos.&lt;/li&gt;
&lt;li&gt;Limitado a los modelos disponibles en su plataforma.&lt;/li&gt;
&lt;li&gt;No permite configuración avanzada, como ajuste fino (fine-tuning).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;OpenRouter&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Funciona como un proxy que da acceso a múltiples modelos (Claude, Mistral, GPT, entre otros).&lt;/li&gt;
&lt;li&gt;Algunos modelos ofrecen un uso gratuito limitado, mientras que otros requieren pago por uso.&lt;/li&gt;
&lt;li&gt;Dispone de una versión gratuita diaria, aunque esta puede agotarse rápidamente si hay alta demanda.&lt;/li&gt;
&lt;li&gt;Mayor flexibilidad de modelos, pero con una experiencia menos homogénea según el proveedor seleccionado.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Cuando accedemos a Continue.dev dentro de Visual Studio Code, inicialmente solo contaremos con un asistente por defecto llamado "My First Assistant". Este asistente viene preconfigurado y es completamente funcional desde el primer momento.&lt;br&gt;
Además, desde el sitio web de Continue.dev, es posible seleccionar otros modelos disponibles con uso limitado gratuito, sin necesidad de configurarlos manualmente. Sin embargo, para un control total y acceso a modelos más potentes o personalizados, lo ideal es editar el archivo config.yaml como vimos anteriormente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcmqjb2w5k3f0i0sywbq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcmqjb2w5k3f0i0sywbq.png" alt="Continue default assistant" width="701" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En nuestro caso, crearemos un agente personalizado de manera local, el cual dependerá directamente de la configuración definida en nuestro archivo config.yaml (como se mostró en la imagen anterior).&lt;/p&gt;

&lt;p&gt;Este archivo será la clave para conectar con proveedores como Groq u OpenRouter, permitiéndonos aprovechar modelos avanzados de lenguaje de forma gratuita o bajo demanda, según el proveedor elegido.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hb8x7dmz4wnpao1wvqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hb8x7dmz4wnpao1wvqh.png" alt="Continue local assistants" width="700" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez que hayamos seleccionado y configurado los modelos que vamos a utilizar dentro de Continue.dev, deberíamos tener una vista similar a la que se muestra en la imagen superior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Con esta configuración, Continue.dev ya estará funcionando correctamente, y solo nos queda comenzar a probar sus funcionalidades: autocompletado, chat o edición, siempre y cuando el modelo seleccionado lo permita.
&lt;/h2&gt;

&lt;p&gt;Ahora continuaremos con Cline. Utilizar esta extensión es mucho más sencillo, siempre y cuando hayamos creado correctamente nuestras API keys en Groq, OpenRouter u otro proveedor de modelos.&lt;/p&gt;

&lt;p&gt;Para agregar un modelo en Cline, simplemente seleccionamos la opción "Use your own API key", y desde ahí podemos conectar el modelo que deseamos utilizar con la extensión.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9ogrsrtwqhcddqj0zoq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9ogrsrtwqhcddqj0zoq.png" alt="Cline" width="696" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si seleccionamos la opción "Get started for free", obtendremos acceso al modelo Claude 3.7 con ciertas limitaciones. Este acceso forma parte del free trial que ofrece Cline, el cual es ideal para hacer pruebas rápidas y conocer el funcionamiento de la herramienta.&lt;/p&gt;

&lt;p&gt;Una vez que se agote el periodo gratuito, podemos continuar usando Cline integrando un proveedor externo, como Groq o OpenRouter, utilizando nuestra propia API key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uprrikmfqk7lb9pv22y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uprrikmfqk7lb9pv22y.png" alt="Cline default settings" width="703" height="941"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recomiendo usar OpenRouter como proveedor dentro de Cline, ya que ofrece una amplia gama de modelos disponibles, como Qwen 2.5, LLaMA 3 o Gemini 2.5 Flash. Es importante tener en cuenta que la disponibilidad de estos modelos puede variar dependiendo del momento en que realices la implementación dentro de VS Code.&lt;/p&gt;

&lt;p&gt;Por lo tanto, es recomendable verificar qué modelos están accesibles al momento de configurar el agente para asegurarse de elegir el más adecuado según las necesidades del proyecto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2baodan72f43v9y8v0aj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2baodan72f43v9y8v0aj.png" alt="cline available providers" width="698" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es importante tener en cuenta que, dado que estamos utilizando modelos opensource, la principal limitación es el tiempo de respuesta o los timeouts, especialmente debido al alto volumen de uso por parte de la comunidad.&lt;/p&gt;

&lt;p&gt;Cline está diseñado específicamente para realizar cambios en tu código, lo que lo convierte en un asistente AI. Ambas extensiones, Continue.dev y Cline, pueden ser particularmente útiles en situaciones donde no tengamos acceso a internet y estemos trabajando con un modelo alojado localmente en nuestra PC.&lt;/p&gt;

&lt;p&gt;Ahora bien, las letras pequeñas de usar un modelo local son las siguientes: deberás seleccionar un modelo que se ajuste a las especificaciones de tu computadora. Es crucial tener en cuenta los recursos de tu equipo (memoria, procesador, etc.) para evitar problemas de rendimiento.&lt;/p&gt;

&lt;p&gt;Cuando trabajamos con un modelo local, podemos integrarlo tanto a Continue.dev como a Cline, lo que nos permite aprovechar las ventajas de ambas herramientas incluso sin conexión a internet.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>continue</category>
      <category>cline</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Internacionalización en Aplicaciones React con i18next</title>
      <dc:creator>Johan Garcia</dc:creator>
      <pubDate>Sat, 18 Jan 2025 22:53:57 +0000</pubDate>
      <link>https://dev.to/devjohanadrian/internacionalizacion-en-aplicaciones-react-con-i18next-286k</link>
      <guid>https://dev.to/devjohanadrian/internacionalizacion-en-aplicaciones-react-con-i18next-286k</guid>
      <description>&lt;p&gt;Cada dia  el mundo esta conectado, ofrecer contenido accesible en múltiples idiomas se ha convertido en una necesidad fundamental para aplicaciones modernas. En este artículo, abordaremos cómo implementar internacionalización en aplicaciones React utilizando i18next, una biblioteca flexible y poderosa para la gestión de traducciones.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;¿Qué es la internacionalización de aplicaciones web?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Con la internacionalización (i18n) damos la capacidad a nuestras aplicaciones de ser adaptables a diferentes idiomas y regiones sin la necesidad de realizar cambios en su código fuente.&lt;/p&gt;

&lt;p&gt;Esto incluye la traducción de textos, la adaptación de formatos de fecha, moneda, números y cualquier otro aspecto que varíe según la localización cultural de los usuarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Qué es i18next y por qué utilizarlo?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;i18next es una solución popular de internacionalización que simplifica la gestión de traducciones en aplicaciones web, móviles y de escritorio. Ofrece soporte para:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Carga dinámica de idiomas.&lt;/li&gt;
&lt;li&gt;Interpolación de variables en textos.&lt;/li&gt;
&lt;li&gt;Gestor de recursos centralizado para traducciones.&lt;/li&gt;
&lt;li&gt;Cambio de idioma en tiempo real.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Existen otras opciones a i18next, como lo son react-intl, LinguiJS, Polyglot.js, MessageFormat.js y Globalize, pero nos centraremos en i18next, ya que es una librería muy popular, cuenta con un buen número de descargas semanales en npm.js y destaca por su simplicidad a la hora de ser configurada en una aplicación de React.js.&lt;/p&gt;

&lt;p&gt;A lo largo de este artículo, exploraremos cómo configurar y utilizar i18next en una aplicación React paso a paso.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Instalación y configuración&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Comenzaremos instalando i18next junto con su paquete adaptador para React:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyrypo53d3gj1jp7ksy3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyrypo53d3gj1jp7ksy3.png" alt="npm install" width="744" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez instalados los paquetes necesarios para la configuración de i18next, configuraremos la instancia principal de i18next en un archivo dedicado, por ejemplo, i18n.js.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3luzdiyslrfu6kxwfjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3luzdiyslrfu6kxwfjr.png" alt="i18n.js." width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora crearemos los archivos que van a contener nuestras traducciones (es.json y en.json). Para ello, crearemos una carpeta en la raíz de nuestro proyecto React.js llamada locale.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbtu0elxs36w4mtdofaw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbtu0elxs36w4mtdofaw.png" alt="folder tree" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;es.JSON&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpk0hbxbmxdo37fy0hag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpk0hbxbmxdo37fy0hag.png" alt="es.JSON" width="744" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;en.JSON&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F590vms14xzka5bp4e8ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F590vms14xzka5bp4e8ma.png" alt="en.JSON" width="744" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Configurar el proveedor global&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Para que las traducciones sean accesibles en toda la aplicación, envolveremos el componente principal con el proveedor I18nextProvider. Este paso se realiza en el archivo principal, como index.jsx.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq93tk6iy5suewpz7irek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq93tk6iy5suewpz7irek.png" alt="index.jsx" width="735" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con esta configuración, todas las traducciones estarán disponibles en los componentes React.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Uso en componentes&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Para traducir textos en los componentes, utilizaremos el hook useTranslation que proporciona react-i18next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu05ny9bvci80r3wi9ela.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu05ny9bvci80r3wi9ela.png" alt="Uso en componentes" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En este ejemplo, t es la función que busca las traducciones en el idioma actual.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Cambiar de idioma&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Podemos implementar una funcionalidad para cambiar el idioma de la aplicación en tiempo real utilizando el método changeLanguage de la instancia de i18next:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F223eblaks6p1j0d3hh1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F223eblaks6p1j0d3hh1f.png" alt="changinglanguage" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con esto, los usuarios podrán alternar entre idiomas sin recargar la aplicación.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusión&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;En este artículo, hemos explorado los fundamentos para implementar internacionalización con i18next en una aplicación React. Hemos configurado el entorno para que funcione con I18nextProvider, pero existen enfoques diferentes, como Context API o HOC (Higher-Order Component). Si desean explorar estos acercamientos, pueden consultarlos en la documentación de &lt;a href="https://react.i18next.com/" rel="noopener noreferrer"&gt;react-i18next.&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rutas relativas y absolutas en programación</title>
      <dc:creator>Johan Garcia</dc:creator>
      <pubDate>Mon, 13 Jan 2025 22:36:45 +0000</pubDate>
      <link>https://dev.to/devjohanadrian/rutas-relativas-y-absolutas-en-programacion-15nh</link>
      <guid>https://dev.to/devjohanadrian/rutas-relativas-y-absolutas-en-programacion-15nh</guid>
      <description>&lt;p&gt;Una ruta es el método mediante el cual podemos referenciar un recurso o directorio en un sistema de archivos dentro de un sistema operativo. Teniendo esto claro, ¿por qué es importante conocer más sobre las rutas? Porque estas te ayudan a evitar errores y a referenciar de forma exacta los recursos o directorios necesarios para ser utilizados en nuestras aplicaciones.&lt;/p&gt;

&lt;p&gt;Al saber indicar la localización exacta de un archivo o directorio mediante una cadena de caracteres, podemos trabajar de manera más eficiente y precisa.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Árbol de directorios&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Antes de continuar, es importante definir un término clave para entender las rutas absolutas y relativas: el árbol de directorios. Este concepto representa una estructura jerárquica de directorios y archivos en un sistema operativo. Es un enfoque común cuando trabajamos directamente con sistemas de archivos, exploradores de carpetas o comandos de terminal, y es independiente de una aplicación específica.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concepto del Árbol de Rutas&lt;/strong&gt;&lt;br&gt;
Un sistema de archivos está organizado en una estructura de árbol, donde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cada nodo es un directorio o un archivo.&lt;/li&gt;
&lt;li&gt;El nodo raíz (/ en sistemas basados en UNIX o una unidad como C:\ en Windows) es el punto de inicio.&lt;/li&gt;
&lt;li&gt;Cada rama conecta un directorio con sus subdirectorios o archivos.&lt;/li&gt;
&lt;li&gt;Cada archivo o directorio tiene una ruta única que describe su posición en el árbol.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Estructura Jerárquica del Árbol&lt;/strong&gt;&lt;br&gt;
La estructura típica de un árbol de rutas en un sistema operativo puede representarse como:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dhh1n2n8e4pke6imd9y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dhh1n2n8e4pke6imd9y.png" alt="Estructura Jerárquica del Árbol" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentro de este árbol de directorios se encuentran las rutas absolutas y relativas, que es lo que veremos a continuación.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rutas Absolutas&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comienzan desde el directorio raíz (/ en sistemas basados en UNIX o C:\ en Windows).&lt;/li&gt;
&lt;li&gt;Proporcionan la localización completa del archivo o directorio en el sistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ejemplos&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;En UNIX: /home/user/documents/file1.txt&lt;/li&gt;
&lt;li&gt;En Windows: C:\Users\User\Documents\file1.txt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rutas Relativas&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se definen en relación con el directorio actual.&lt;/li&gt;
&lt;li&gt;Ejemplo: Si estás en /home/user, la ruta relativa a file1.txt sería documents/file1.txt.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Rutas&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Existen dos formas de expresar una ruta, su forma relativa y su forma absoluta que cumplen funciones distintas, en su mayoria las rutas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rutas Relativas&lt;/strong&gt;&lt;br&gt;
Una ruta relativa indica la ubicación de un archivo o recurso en relación con el directorio actual, o lo que sería lo mismo, la posición en la que nos encontramos dentro del sistema operativo (o el contexto actual). Estas rutas son más flexibles y se utilizan para acceder a archivos más cercanos o relacionados con la misma jerarquía de directorios en la que estamos trabajando.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referenciación&lt;/strong&gt;&lt;br&gt;
Utilizaremos . para referenciar el directorio actual. Es útil para referirse a archivos o subdirectorios dentro del mismo directorio donde estás ubicado.&lt;/p&gt;

&lt;p&gt;Utilizaremos .. para referenciar al directorio padre. Representa el directorio inmediatamente superior al actual.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ejemplos&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;../file.txt se refiere a file.txt en el directorio padre.&lt;/li&gt;
&lt;li&gt;../../anotherfile.txt retrocede dos niveles en la jerarquía y busca el archivo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tomaremos este directorio como ejemplo para explicar el uso de rutas relativas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft08h3mlxjkqyi6nwb71l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft08h3mlxjkqyi6nwb71l.png" alt="Directorio de ejemplo" width="570" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Supongamos que estamos trabajando dentro de Header.js y queremos utilizar las funcionalidades que se encuentran en helpers.js. Haríamos referencia de la siguiente forma:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07mlsz0o7ik5hg6r38fl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07mlsz0o7ik5hg6r38fl.png" alt="Importacion de recursos" width="744" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Las ventajas de utilizar las rutas relativas son que no requieren un conocimiento completo de la estructura global del árbol de directorios.&lt;/p&gt;

&lt;p&gt;Una desventaja sería utilizarlas en proyectos grandes, donde puede ser difícil mantener rutas que son especialmente largas, como (../../../).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rutas Absolutas&lt;/strong&gt;&lt;br&gt;
Una ruta absoluta indica o señala la ubicación completa de un archivo, recurso o directorio desde la raíz del sistema de archivos. Estas rutas son independientes del directorio actual, más claras y explícitas sobre la ubicación del recurso. Además, pueden ser configuradas en algunos entornos, como TypeScript o Webpack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ejemplo&lt;/strong&gt;&lt;br&gt;
Si no estuviéramos trabajando con TypeScript o Webpack, haríamos uso de la raíz de nuestro árbol de archivos para ubicarnos en el recurso que necesitáramos (por ejemplo: C:\usuarios\usuario1\project\src\utils\helpers).&lt;/p&gt;

&lt;p&gt;Sin embargo, en este caso estaremos utilizando TypeScript y haremos uso de baseUrl en tsconfig.json para configurar una URL base desde la cual podemos partir al utilizar rutas absolutas dentro de nuestro proyecto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85buxgsmvjxbcuds00pe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85buxgsmvjxbcuds00pe.png" alt="Directorio de ejemplo con tsconfig" width="640" height="708"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora continuaremos con la configuración de nuestro &lt;strong&gt;tsconfig.json&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq3i4jz359e3vr04bopi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq3i4jz359e3vr04bopi.png" alt="Configuracion de tsconfig" width="744" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con esta configuración dentro de TypeScript y tsconfig.json, podremos utilizar los alias en nuestras rutas absolutas sin necesidad de referenciar todo el árbol de rutas existente (C:\usuarios\usuario1\project\src\utils\helpers), lo que evitará definir rutas extensas y difíciles de mantener, o el uso de rutas relativas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusión&lt;/strong&gt;&lt;br&gt;
Es esencial que comprendamos el árbol de directorios y las diferencias entre las rutas relativas y absolutas, ya que este conocimiento facilitará enormemente la navegación y gestión de archivos en cualquier sistema operativo o entorno de desarrollo. Las rutas absolutas les ofrecen una referencia precisa y clara a archivos y directorios, lo que asegura que siempre puedan acceder a ellos sin depender del directorio en el que se encuentren. Por otro lado, las rutas relativas son ideales para trabajar dentro del mismo contexto o proyecto, proporcionando flexibilidad y simplicidad.&lt;/p&gt;

&lt;p&gt;Saber cuándo y cómo utilizar cada tipo de ruta no solo mejora la organización de sus proyectos, sino que también optimiza la mantenibilidad y reduce los errores relacionados con la ubicación de recursos. En proyectos grandes, las rutas absolutas y los alias bien configurados pueden simplificar las referencias y hacer que el código sea más limpio y fácil de comprender.&lt;/p&gt;

&lt;p&gt;Entender estos conceptos es crucial para mejorar la eficiencia y precisión al trabajar con archivos y al desarrollar aplicaciones, garantizando un flujo de trabajo más ágil y un código más robusto.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si el proyecto es pequeño o no quieres modificar configuraciones, usa rutas relativas.&lt;/li&gt;
&lt;li&gt;Si trabajas en un proyecto grande o quieres mejorar la claridad del código, configura rutas absolutas.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
