<?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: Christian Gonzales Komiya</title>
    <description>The latest articles on DEV Community by Christian Gonzales Komiya (@ckomiya).</description>
    <link>https://dev.to/ckomiya</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%2F3976243%2F7ae6966c-9d81-4d32-ad97-3215224dc563.png</url>
      <title>DEV Community: Christian Gonzales Komiya</title>
      <link>https://dev.to/ckomiya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ckomiya"/>
    <language>en</language>
    <item>
      <title>(Spanish) El navegador ya no es solo para humanos</title>
      <dc:creator>Christian Gonzales Komiya</dc:creator>
      <pubDate>Thu, 25 Jun 2026 23:36:21 +0000</pubDate>
      <link>https://dev.to/ckomiya/el-navegador-ya-no-es-solo-para-humanos-1e6g</link>
      <guid>https://dev.to/ckomiya/el-navegador-ya-no-es-solo-para-humanos-1e6g</guid>
      <description>&lt;p&gt;&lt;em&gt;Por qué las páginas web públicas son ahora accesibles de formas que antes eran impensables&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Hubo un tiempo en que "ver algo en una web" y "usar ese dato en código" eran dos mundos separados. El primero era para humanos. El segundo requería que la empresa dueña del sitio te diera una API, documentación, credenciales, y su bendición.&lt;/p&gt;

&lt;p&gt;Ese tiempo terminó.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Lo que descubrí explorando
&lt;/h2&gt;

&lt;p&gt;Estaba analizando cómo obtener datos de una página web pública — sin registro, sin login, sin nada que el usuario promedio no pudiera ver con sus propios ojos. Información completamente pública.&lt;/p&gt;

&lt;p&gt;El camino obvio parecía ser el scraping tradicional: descargar el HTML, parsear el contenido. Pero la web moderna no funciona así. La mayoría de sitios hoy son &lt;strong&gt;Single Page Applications&lt;/strong&gt; — React, Angular, Vue — donde el HTML inicial está vacío y el contenido llega después, cargado dinámicamente por JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eso es todo lo que ves si intentas descargar el HTML directamente. Un div vacío esperando que JavaScript haga su trabajo.&lt;/p&gt;




&lt;h2&gt;
  
  
  La API interna que nadie documenta
&lt;/h2&gt;

&lt;p&gt;Abrí las herramientas de desarrollo del browser, filtré por Fetch/XHR, y observé el tráfico. Lo que vi fue revelador: la app de React estaba consumiendo una &lt;strong&gt;API interna&lt;/strong&gt; con endpoints bien estructurados, respuestas en JSON limpio, y toda la información organizada perfectamente.&lt;/p&gt;

&lt;p&gt;Datos que visualmente aparecen en pantalla para cualquier usuario, pero que internamente viajan como JSON estructurado, listo para ser procesado.&lt;/p&gt;

&lt;p&gt;El problema: esa API tenía protección. Un WAF (Web Application Firewall) en Azure que analizaba cada request y bloqueaba cualquier cosa que no pareciera un browser legítimo. Tokens de sesión con expiración. Cookies generadas dinámicamente. Un ecosistema de seguridad diseñado para que solo browsers reales pudieran consumir esos datos.&lt;/p&gt;

&lt;p&gt;Y tenía razón en bloquearte — si intentabas replicar el request manualmente, para cuando copiabas todos los headers necesarios, los tokens ya habían vencido.&lt;/p&gt;




&lt;h2&gt;
  
  
  El agente como humano digital
&lt;/h2&gt;

&lt;p&gt;Aquí entra el cambio de paradigma.&lt;/p&gt;

&lt;p&gt;Un agente con control de browser — usando herramientas como Playwright — no simula un request. &lt;strong&gt;Abre un browser real&lt;/strong&gt;. Chromium de verdad. Navega como lo haría un usuario. Las cookies se generan naturalmente. Los tokens están vigentes. El WAF ve exactamente lo que espera ver.&lt;/p&gt;

&lt;p&gt;Pero a diferencia del humano, el agente puede hacer algo que el humano no puede: &lt;strong&gt;obtener y usar los datos en el mismo instante, dentro del mismo contexto de sesión&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El flujo es así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agente abre browser
    → navega al sitio (tokens se generan automáticamente)
    → intercepta la respuesta de la API en tiempo real
    → extrae los datos estructurados
    → los guarda en base de datos
    → cierra el browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Todo en segundos. Sin que ningún token tenga tiempo de vencer. Sin que ningún WAF detecte anomalías. Porque técnicamente no hay ninguna.&lt;/p&gt;




&lt;h2&gt;
  
  
  El problema del humano vs. el agente
&lt;/h2&gt;

&lt;p&gt;Cuando un humano intenta hacer esto manualmente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abre DevTools&lt;/li&gt;
&lt;li&gt;Filtra el tráfico de red&lt;/li&gt;
&lt;li&gt;Encuentra el request correcto&lt;/li&gt;
&lt;li&gt;Copia los headers&lt;/li&gt;
&lt;li&gt;Los pega en un cliente HTTP&lt;/li&gt;
&lt;li&gt;Ejecuta el request&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Resultado:&lt;/strong&gt; Token vencido. Request bloqueado.&lt;/p&gt;

&lt;p&gt;El tiempo que tarda el humano en completar esos pasos es mayor que el tiempo de vida de los tokens de sesión. Es una carrera que el humano pierde por diseño.&lt;/p&gt;

&lt;p&gt;Cuando el agente hace lo mismo, no hay pasos separados. La obtención y el uso son &lt;strong&gt;una sola operación continua&lt;/strong&gt;. El agente no anota el token para usarlo después — lo usa mientras aún está caliente, en el mismo contexto donde nació.&lt;/p&gt;




&lt;h2&gt;
  
  
  ¿Es esto vulnerar algo?
&lt;/h2&gt;

&lt;p&gt;No. Y esa es la parte más interesante del análisis.&lt;/p&gt;

&lt;p&gt;Cualquier información que una página muestra públicamente, sin requerir autenticación, es información que el usuario tiene derecho a ver. El agente no hace nada que el usuario no pudiera hacer manualmente — simplemente lo hace más rápido y de forma programática.&lt;/p&gt;

&lt;p&gt;La línea ética está clara:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Información pública, uso personal o académico&lt;/strong&gt; → completamente legítimo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatización masiva que sature servidores&lt;/strong&gt; → problemático&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uso comercial de datos ajenos&lt;/strong&gt; → requiere revisar términos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acceso a cuentas de terceros&lt;/strong&gt; → ilegal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;8 requests al día para leer información pública genera menos tráfico que un usuario humano visitando el sitio dos veces. No hay daño, no hay saturación, no hay violación.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lo que esto significa para el desarrollo
&lt;/h2&gt;

&lt;p&gt;Estamos en un momento donde la barrera entre "ver datos" y "usar datos en código" prácticamente desapareció para información pública.&lt;/p&gt;

&lt;p&gt;Antes necesitabas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Una API oficial con documentación&lt;/li&gt;
&lt;li&gt;Credenciales y proceso de registro&lt;/li&gt;
&lt;li&gt;Límites de uso negociados&lt;/li&gt;
&lt;li&gt;Meses de espera para aprobación&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ahora necesitas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un agente con Playwright&lt;/li&gt;
&lt;li&gt;Decirle qué quieres obtener&lt;/li&gt;
&lt;li&gt;Esperar segundos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Las implicancias para el desarrollo de software son enormes. Cualquier fuente de datos pública se convierte potencialmente en una fuente estructurada para tus aplicaciones. Sin fricción. Sin burocracia. Sin depender de que la empresa decida publicar una API.&lt;/p&gt;




&lt;h2&gt;
  
  
  La arquitectura que emerge
&lt;/h2&gt;

&lt;p&gt;Lo interesante no es solo obtener los datos una vez — es cómo esto se integra en una arquitectura completa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agente recopilador (cron programado)
    → navega fuentes públicas
    → extrae datos estructurados
    → guarda en base de datos local

MCP Server
    → lee la base de datos
    → expone herramientas al agente de consulta

Usuario
    → pregunta en lenguaje natural
    → el agente consulta las herramientas
    → respuesta instantánea desde datos frescos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El agente recopilador y el agente de consulta son independientes. Uno escribe, el otro lee. La base de datos es el punto de encuentro. Y el usuario final nunca sabe — ni necesita saber — de dónde vienen los datos.&lt;/p&gt;




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

&lt;p&gt;Las páginas web públicas siempre fueron accesibles para humanos. Lo nuevo es que ahora son igualmente accesibles para agentes — y en algunos aspectos, el agente las maneja mejor que el humano.&lt;/p&gt;

&lt;p&gt;No porque rompa barreras de seguridad. Sino porque opera dentro de los mismos canales legítimos que usa cualquier browser, pero sin las limitaciones de tiempo y coordinación que tiene un humano copiando y pegando headers.&lt;/p&gt;

&lt;p&gt;El browser ya no es solo para humanos. Y eso cambia bastante cómo pensamos el acceso a datos en el desarrollo moderno.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Este post es parte de una exploración práctica sobre agentes de IA. Las conclusiones son aplicables a cualquier fuente de información pública en la web.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>web</category>
      <category>webdev</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>(Spanish) [App] Visualización de Denuncias en el mapa del Perú - Uso de Streamlit + Pandas + Folium</title>
      <dc:creator>Christian Gonzales Komiya</dc:creator>
      <pubDate>Tue, 09 Jun 2026 15:30:56 +0000</pubDate>
      <link>https://dev.to/ckomiya/spanish-app-visualizacion-de-denuncias-en-el-mapa-del-peru-uso-de-streamlit-pandas-folium-1f74</link>
      <guid>https://dev.to/ckomiya/spanish-app-visualizacion-de-denuncias-en-el-mapa-del-peru-uso-de-streamlit-pandas-folium-1f74</guid>
      <description>&lt;p&gt;En los últimos meses, la inseguridad ciudadana en el Perú ha ido en aumento.&lt;br&gt;
&amp;nbsp;Quise explorar una manera simple y accesible de visualizar esta problemática usando datos abiertos y herramientas de análisis de datos.&lt;br&gt;
Este es un pequeño proyecto motivado por un dataset de denuncias policiales publicado por la Policía Nacional del Perú en la plataforma oficial de datos abiertos del Estado Peruano.&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%2Flzf3rrl2d6k2adknvp5y.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%2Flzf3rrl2d6k2adknvp5y.png" alt=" " width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dataset utilizado&lt;/strong&gt;: Denuncias Policiales - Enero 2018 a Junio 2025&lt;br&gt;
&amp;nbsp;(También lo puedes encontrar buscando "Denuncia" en datosabiertos.gob.pe)&lt;/p&gt;

&lt;p&gt;El dataset incluye (al corte de agosto 2025) modalidades como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Estafa&lt;/li&gt;
&lt;li&gt;Extorsión&lt;/li&gt;
&lt;li&gt;Homicidio&lt;/li&gt;
&lt;li&gt;Hurto&lt;/li&gt;
&lt;li&gt;Robo&lt;/li&gt;
&lt;li&gt;Violencia contra la mujer&lt;/li&gt;
&lt;li&gt;Otros&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Link de la app -&amp;gt; &lt;a href="https://denuncias-pnp.streamlit.app/" rel="noopener noreferrer"&gt;https://denuncias-pnp.streamlit.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎯 Motivación&lt;br&gt;
La idea nació como una forma de:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Analizar cómo han evolucionado las denuncias en el tiempo.&lt;/li&gt;
&lt;li&gt;Ubicarlas en un mapa para identificar zonas con mayor incidencia.&lt;/li&gt;
&lt;li&gt;Darle un formato visual e interactivo, aprovechando herramientas de código abierto.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🛠 Herramientas utilizadas&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Streamlit → Framework en Python que permite crear aplicaciones web interactivas para análisis de datos de forma rápida y sencilla.&lt;/li&gt;
&lt;li&gt;Pandas → Librería para manipulación y análisis de datos en Python. Ideal para trabajar con tablas, filtrar y agrupar datos.&lt;/li&gt;
&lt;li&gt;Folium → Librería para generar mapas interactivos en Python usando Leaflet.js.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🌍 Visualización en mapa&lt;br&gt;
La parte más llamativa del proyecto es la representación geográfica de las denuncias.&lt;br&gt;
&amp;nbsp;A partir de los datos filtrados por año y tipo de modalidad, se agrupan las denuncias por distrito y se dibujan círculos proporcionales a la cantidad de casos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# --- Mapa por distrito ---
&lt;/span&gt;&lt;span class="n"&gt;df_map_filt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ANIO&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;modalidad&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Todas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;df_map_filt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df_map_filt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df_map_filt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;P_MODALIDADES&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;modalidad&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;df_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;df_map_filt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UBIGEO_HECHO&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as_index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cantidad&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;df_ubigeo&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inei&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distrito&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
        &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UBIGEO_HECHO&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inei&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;left&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dropna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subheader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🌍 Mapa por distrito&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;folium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;9.19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;75.02&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;zoom_start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;max_c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cantidad&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;df_map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iterrows&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cantidad&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;max_c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;max_c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;folium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CircleMarker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
        &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;crimson&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fill_opacity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;popup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;distrito&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cantidad&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;add_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;st_folium&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Qué hace este código:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Filtra las denuncias por año y modalidad.&lt;/li&gt;
&lt;li&gt;Agrupa por distrito (usando el código UBIGEO) y suma la cantidad de casos.&lt;/li&gt;
&lt;li&gt;Une la información con coordenadas geográficas para cada distrito.&lt;/li&gt;
&lt;li&gt;Crea un mapa con círculos rojos cuyo tamaño es proporcional a la cantidad de denuncias.&lt;/li&gt;
&lt;li&gt;Muestra un popup con el nombre del distrito y el número de denuncias.&lt;/li&gt;
&lt;/ol&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%2Fdef16b7qnp1xxsmj2hr9.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%2Fdef16b7qnp1xxsmj2hr9.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📈 Gráfico de tendencia por tipo de denuncia&lt;br&gt;
Además del mapa, la aplicación muestra un gráfico de tendencia donde se observa la evolución de cada tipo de denuncia a lo largo de los años, desglosado por departamento.&lt;br&gt;
&amp;nbsp;Esto permite identificar patrones, por ejemplo, si ciertos delitos han ido aumentando o disminuyendo con el tiempo.&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%2F2ujnihtdd303abhd7paz.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%2F2ujnihtdd303abhd7paz.png" alt=" " width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📦 Código fuente&lt;br&gt;
El código completo y los datos procesados están disponibles en mi repositorio de GitHub:&lt;br&gt;
&amp;nbsp;🔗 &lt;a href="https://github.com/ckomiya/data_science_denuncias_pnp" rel="noopener noreferrer"&gt;https://github.com/ckomiya/data_science_denuncias_pnp&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>(Spanish) Arquitectura Hexagonal (Ports &amp; Adapters) - Beneficios y Ejemplo en Java</title>
      <dc:creator>Christian Gonzales Komiya</dc:creator>
      <pubDate>Tue, 09 Jun 2026 15:22:23 +0000</pubDate>
      <link>https://dev.to/ckomiya/spanish-arquitectura-hexagonal-ports-adapters-beneficios-y-ejemplo-en-java-711</link>
      <guid>https://dev.to/ckomiya/spanish-arquitectura-hexagonal-ports-adapters-beneficios-y-ejemplo-en-java-711</guid>
      <description>&lt;p&gt;Mientras leía el libro &lt;em&gt;Hexagonal Architecture Explained&lt;/em&gt; de Alistair Cockburn y Juan Manuel Garrido, me encontré con una sección que destaca beneficios clave de este patrón.&lt;br&gt;&lt;br&gt;
En este artículo represento en código Java los &lt;strong&gt;tres pasos esenciales&lt;/strong&gt; para implementar la arquitectura y lograr dichos beneficios.&lt;/p&gt;


&lt;h2&gt;
  
  
  Beneficios destacados
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;El sistema queda abierto a tener &lt;strong&gt;pruebas de regresión&lt;/strong&gt; para todas sus funciones, de extremo a extremo.&lt;/li&gt;
&lt;li&gt;Es posible &lt;strong&gt;variar las tecnologías externas&lt;/strong&gt; conforme evolucionan (como siempre lo hacen) sin un esfuerzo enorme.&lt;/li&gt;
&lt;li&gt;Estos dos beneficios adicionales superan fácilmente el pequeño costo extra de implementar la solución.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Paso 1 – API del sistema (interfaz proporcionada)
&lt;/h2&gt;

&lt;p&gt;Creamos la aplicación para que sus servicios estén disponibles como llamadas a funciones, sin depender directamente de UI o base de datos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Paso 1: API del sistema (interfaz proporcionada)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaxCalculatorApp&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Servicio principal expuesto como API&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;calculateTax&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí la aplicación no sabe nada de dónde viene el rate ni de si hay base de datos: es solo lógica pura.&lt;/p&gt;




&lt;h2&gt;
  
  
  Paso 2 – Variables para las conexiones externas (interfaces requeridas)
&lt;/h2&gt;

&lt;p&gt;Agregamos variables para cada conexión externa (por ejemplo, un servicio que da la tasa de impuestos).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Interfaz requerida: servicio externo para obtener tasa de impuestos&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;TaxRateProvider&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;getTaxRate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Paso 2: la aplicación ahora tiene una variable para su conexión externa&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaxCalculatorApp&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Variable para el proveedor de tasas (actor secundario)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TaxRateProvider&lt;/span&gt; &lt;span class="n"&gt;taxRateProvider&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Inyectamos la dependencia (aún puede ser null si no se configura)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setTaxRateProvider&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TaxRateProvider&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;taxRateProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Servicio principal usa la interfaz requerida&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;calculateTax&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taxRateProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTaxRate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora la aplicación no llama directamente a un servicio concreto: usa una interfaz requerida (&lt;code&gt;TaxRateProvider&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  Paso 3 – Configuración con actores reales o adaptadores (inyección de dependencias)
&lt;/h2&gt;

&lt;p&gt;En la construcción/configuración, conectamos la app con un adaptador concreto, o con un doble de pruebas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Adaptador concreto que obtiene tasa desde una BD (ejemplo simple)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseTaxRateAdapter&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;TaxRateProvider&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;getTaxRate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Aquí iría la lógica real de conexión a base de datos&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.21&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Ejemplo: IVA 21%&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Adaptador doble de pruebas&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FixedTaxRateStub&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;TaxRateProvider&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;fixedRate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FixedTaxRateStub&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;fixedRate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fixedRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fixedRate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;getTaxRate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fixedRate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Paso 3: Configuración y uso&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;TaxCalculatorApp&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TaxCalculatorApp&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configuración para producción&lt;/span&gt;
        &lt;span class="nc"&gt;TaxRateProvider&lt;/span&gt; &lt;span class="n"&gt;dbAdapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DatabaseTaxRateAdapter&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTaxRateProvider&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbAdapter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Impuesto: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculateTax&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Configuración para pruebas&lt;/span&gt;
        &lt;span class="nc"&gt;TaxRateProvider&lt;/span&gt; &lt;span class="n"&gt;testStub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FixedTaxRateStub&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTaxRateProvider&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testStub&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Impuesto (prueba): "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculateTax&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ Qué logramos siguiendo los pasos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;La app expone su lógica a través de una API clara (&lt;code&gt;calculateTax&lt;/code&gt;), sin UI ni BD acoplada.&lt;/li&gt;
&lt;li&gt;Creamos variables para las dependencias externas (&lt;code&gt;TaxRateProvider&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Conectamos esas dependencias en tiempo de configuración, ya sea con adaptadores reales o dobles de prueba.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>java</category>
      <category>spanish</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>(Spanish) Cómo iniciar un proyecto con Claude Code</title>
      <dc:creator>Christian Gonzales Komiya</dc:creator>
      <pubDate>Tue, 09 Jun 2026 15:01:25 +0000</pubDate>
      <link>https://dev.to/ckomiya/como-iniciar-un-proyecto-con-claude-code-46he</link>
      <guid>https://dev.to/ckomiya/como-iniciar-un-proyecto-con-claude-code-46he</guid>
      <description>&lt;p&gt;Guía rápida para desarrolladores que quieren arrancar un proyecto de forma ordenada y sacarle el máximo provecho a Claude Code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Este artículo no pretende ser una guía exhaustiva — es mi guía de bolsillo personal. La escribí para consultarla cada vez que inicio un proyecto nuevo y no querer recordar de memoria qué pasos seguir. Si te sirve a ti también, genial.&lt;/p&gt;

&lt;p&gt;Fuente: &lt;em&gt;Claude Code Advanced&lt;/em&gt; de Javier Rayon.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Paso 1 — Pre-Setup: prepara el terreno
&lt;/h2&gt;

&lt;p&gt;Antes de escribir una sola línea de código, pídele a Claude que configure la estructura del proyecto.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Estoy comenzando un proyecto de [descripción]. Antes de programar, ayúdame a crear:
- Estructura de directorios
- CLAUDE.md con convenciones
- Scripts de desarrollo (dev, test, build)
- Configuración de linting y formateo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude generará algo así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;my-project/
&lt;span class="p"&gt;-&lt;/span&gt; src/
&lt;span class="p"&gt;    -&lt;/span&gt; routes/
&lt;span class="p"&gt;    -&lt;/span&gt; services/
&lt;span class="p"&gt;    -&lt;/span&gt; models/
&lt;span class="p"&gt;    -&lt;/span&gt; utils/
&lt;span class="p"&gt;-&lt;/span&gt; tests/
&lt;span class="p"&gt;-&lt;/span&gt; scripts/
&lt;span class="p"&gt;-&lt;/span&gt; .claude/
&lt;span class="p"&gt;    -&lt;/span&gt; settings.json
&lt;span class="p"&gt;    -&lt;/span&gt; CLAUDE.md
&lt;span class="p"&gt;    -&lt;/span&gt; rules/
&lt;span class="p"&gt;        -&lt;/span&gt; testing.md
&lt;span class="p"&gt;        -&lt;/span&gt; api-patterns.md
&lt;span class="p"&gt;        -&lt;/span&gt; security.md
&lt;span class="p"&gt;    -&lt;/span&gt; skills/
&lt;span class="p"&gt;        -&lt;/span&gt; deploy/skill.md
&lt;span class="p"&gt;        -&lt;/span&gt; db-migrate/skill.md
&lt;span class="p"&gt;    -&lt;/span&gt; agents/
&lt;span class="p"&gt;        -&lt;/span&gt; reviewer.md
&lt;span class="p"&gt;        -&lt;/span&gt; qa.md
&lt;span class="p"&gt;    -&lt;/span&gt; commands/
&lt;span class="p"&gt;        -&lt;/span&gt; COMMANDS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada carpeta tiene un propósito claro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rules/&lt;/code&gt; — lo que Claude siempre debe respetar (frameworks, patrones, seguridad)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skills/&lt;/code&gt; — procedimientos reutilizables (deploy, migraciones)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agents/&lt;/code&gt; — roles especializados (revisor de código, QA)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;commands/&lt;/code&gt; — comandos slash personalizados (&lt;code&gt;/deploy&lt;/code&gt;, &lt;code&gt;/migrate&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ejemplo de regla&lt;/strong&gt; (&lt;code&gt;.claude/rules/testing.md&lt;/code&gt;):&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="gh"&gt;# Reglas de Testing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Framework: vitest (NUNCA jest)
&lt;span class="p"&gt;-&lt;/span&gt; Convención de nombres: &lt;span class="err"&gt;*&lt;/span&gt;.test.ts
&lt;span class="p"&gt;-&lt;/span&gt; Toda función pública debe tener al menos una prueba
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ejemplo de skill&lt;/strong&gt; (&lt;code&gt;.claude/skills/deploy/skill.md&lt;/code&gt;):&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="gh"&gt;# Desplegar a Producción&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Ejecutar pruebas: &lt;span class="sb"&gt;`npm test`&lt;/span&gt;
&lt;span class="p"&gt;2.&lt;/span&gt; Compilar: &lt;span class="sb"&gt;`npm run build`&lt;/span&gt;
&lt;span class="p"&gt;3.&lt;/span&gt; Verificar que no haya cambios sin commit
&lt;span class="p"&gt;4.&lt;/span&gt; Ejecutar: &lt;span class="sb"&gt;`./scripts/deploy.sh production`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Agrega &lt;code&gt;.claude/worktrees/&lt;/code&gt; a tu &lt;code&gt;.gitignore&lt;/code&gt; desde el inicio.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Paso 2 — Plan: define qué vas a construir
&lt;/h2&gt;

&lt;p&gt;Con el proyecto configurado, entra en modo planificación antes de tocar código.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude analizará el problema y presentará un plan detallado sin modificar nada todavía. Tú revisas, ajustas y le das luz verde.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt vago (evitar):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build a login system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Prompt específico (usar):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plan an OAuth2 login implementation (Google and GitHub).
Requirements:
- JWT with refresh tokens
- 24h expiration
- Rate limiting of 5 attempts per minute
- E2E tests with Playwright
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Técnica avanzada — revisión cruzada:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usa dos sesiones de Claude en paralelo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sesión A genera el plan completo.&lt;/li&gt;
&lt;li&gt;Sesión B lo revisa con este prompt:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Revisa este plan como si fueras un Staff Engineer.
Busca puntos débiles, casos límite no considerados
y dependencias faltantes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ajusta el plan con el feedback de la Sesión B antes de ejecutar.&lt;/p&gt;




&lt;h2&gt;
  
  
  Paso 3 — Worktrees: ejecuta en paralelo
&lt;/h2&gt;

&lt;p&gt;Con el plan listo, identifica 3 a 5 tareas que puedan avanzar simultáneamente y crea un worktree para cada una.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opción A — Worktrees manuales (control total):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feature/auth ../wt-auth main
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feature/api ../wt-api main
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;/e2e ../wt-tests main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego lanza Claude en cada uno:&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="c"&gt;# Terminal 1&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../wt-auth &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; claude

&lt;span class="c"&gt;# Terminal 2&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../wt-api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; claude

&lt;span class="c"&gt;# Terminal 3&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../wt-tests &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Opción B — Worktrees nativos de Claude (más rápido):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--worktree&lt;/span&gt; auth-feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude crea la rama, el directorio y la sesión en un solo paso. Al terminar, limpia automáticamente si no hubo cambios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flujo de cierre:&lt;/strong&gt;&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="c"&gt;# Cada worktree hace commit y crea su PR&lt;/span&gt;
git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: auth OAuth2"&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Auth OAuth2"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"Descripción"&lt;/span&gt;

&lt;span class="c"&gt;# Al terminar todos, limpia&lt;/span&gt;
git worktree remove ../wt-auth
git worktree prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Si en lugar de tareas puntuales necesitas cambios masivos en todo el proyecto (por ejemplo, migrar 50 archivos), usa &lt;code&gt;/batch&lt;/code&gt; en lugar de worktrees manuales — Claude los gestiona automáticamente.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resumen
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Paso&lt;/th&gt;
&lt;th&gt;Qué haces&lt;/th&gt;
&lt;th&gt;Herramienta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pre-Setup&lt;/td&gt;
&lt;td&gt;Configuras estructura, reglas, skills y agentes&lt;/td&gt;
&lt;td&gt;Prompt inicial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan&lt;/td&gt;
&lt;td&gt;Defines qué construir y lo validas&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/plan&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worktrees&lt;/td&gt;
&lt;td&gt;Ejecutas tareas en paralelo&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git worktree&lt;/code&gt; / &lt;code&gt;claude --worktree&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>spanish</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
