<?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: Sazardev</title>
    <description>The latest articles on DEV Community by Sazardev (@sazardev).</description>
    <link>https://dev.to/sazardev</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F432785%2F12bd369a-8f40-433f-80a1-577b900fb445.jpeg</url>
      <title>DEV Community: Sazardev</title>
      <link>https://dev.to/sazardev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sazardev"/>
    <language>en</language>
    <item>
      <title>I finally built the Go project generator I always wanted: Goca (Beta)</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Wed, 29 Oct 2025 14:24:14 +0000</pubDate>
      <link>https://dev.to/sazardev/i-finally-built-the-go-project-generator-i-always-wanted-goca-beta-5ec8</link>
      <guid>https://dev.to/sazardev/i-finally-built-the-go-project-generator-i-always-wanted-goca-beta-5ec8</guid>
      <description>&lt;p&gt;Hey Devs!, I wanted to share a side project I’ve been pouring time into lately: Goca.&lt;/p&gt;

&lt;p&gt;If you’re like me, you’re tired of writing the same 20 files just to start a new Go service following Clean Architecture. The layers, the interfaces, the DI config—it’s necessary, but it’s pure boilerplate.&lt;/p&gt;

&lt;p&gt;That’s where Goca comes in. It’s a CLI tool that generates a full, production-ready Go feature (entity, use case, repository, HTTP handler) in seconds, all while strictly enforcing Uncle Bob’s Clean Architecture rules. It’s essentially my way of cutting out the setup tax.&lt;/p&gt;

&lt;p&gt;Heads up: This is still very much in beta. It’s working great for my own projects, but there are definitely rough edges, and I’m still figuring out the best ways to handle database migrations and multi-protocol setups.&lt;/p&gt;

&lt;p&gt;It’s open source (MIT licensed), and I’m genuinely looking for feedback from people who actually build production Go apps. If you hate boilerplate as much as I do, please check out the documentation and let me know where it breaks for you.&lt;/p&gt;

&lt;p&gt;Link to the docs:&lt;a href="https://sazardev.github.io/goca/" rel="noopener noreferrer"&gt;https://sazardev.github.io/goca/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>cleancode</category>
      <category>cli</category>
    </item>
    <item>
      <title>Transform Business Productivity with DevOps Culture</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Mon, 15 Sep 2025 17:56:18 +0000</pubDate>
      <link>https://dev.to/sazardev/transform-business-productivity-with-devops-culture-49ah</link>
      <guid>https://dev.to/sazardev/transform-business-productivity-with-devops-culture-49ah</guid>
      <description>&lt;p&gt;When someone hears the term "&lt;em&gt;DevOps&lt;/em&gt;", they often think of a branch of software engineering that sounds complex and very technical, and that only concerns system engineers. How naive people can be sometimes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DevOps&lt;/em&gt; is much more than a fancy-sounding job title; it is a culture, a work philosophy that every company wanting to be competitive in today's market should have. This is because &lt;em&gt;DevOps&lt;/em&gt; has a very precise philosophy: "Automate everything that can be automated and measure everything that can be measured."&lt;/p&gt;

&lt;p&gt;I have seen hundreds of times people, teams, departments, and even companies fall into overengineering, creating unnecessary processes and procedures, generating bureaucracy and paperwork that add no value to the product or service being offered. This is, absolutely, the death of productivity and efficiency.&lt;/p&gt;

&lt;p&gt;Imagine (or not, if this has happened to you) that you need to book a meeting room. The first thing they'll ask you to do is fill out a form, then send it to your boss for approval, then the boss sends it to HR for their approval, then HR manually checks a calendar of rooms and confirms if the room is available, then you get a confirmation email, and finally, you go to the room to book it physically. All of this must be notified to everyone involved.&lt;/p&gt;

&lt;p&gt;After so much bureaucratic process, guess what happened: someone in HR forgot to book the room and, when you arrived, it was occupied by another meeting.&lt;/p&gt;

&lt;p&gt;This is a clear example of overengineering and bureaucracy that adds no value to the process of booking a room. If an automated system had been implemented for booking rooms, all this bureaucracy would have been avoided, saving time and effort for everyone involved. Also, a motto to remember when talking about &lt;em&gt;DevOps&lt;/em&gt; is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If something can go wrong, it will go wrong" - Murphy's Law&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's inevitable, and you may think it's a bit pessimistic, but it's reality. Humans are prone to making mistakes, no matter how careful they are. That's why it's important to automate everything that can be automated and measure everything that can be measured, to minimize the human factor in a company's processes and procedures. It's important to note that automation is not just for technical processes, but also for administrative and business processes. The &lt;em&gt;DevOps&lt;/em&gt; culture should permeate the entire company, from the CEO to the last employee. Stop thinking it's something that only concerns system engineers and start thinking about how you can implement the &lt;em&gt;DevOps&lt;/em&gt; culture in your company to be more efficient and competitive in today's market.&lt;/p&gt;




&lt;p&gt;Now that it's clear that &lt;em&gt;DevOps&lt;/em&gt; is a culture that should permeate the entire company, it's important to understand how to implement it. Here are some steps to implement the &lt;em&gt;DevOps&lt;/em&gt; culture in a company:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automate everything that can be automated&lt;/strong&gt;: Identify the processes and procedures that can be automated and look for tools and technologies to do so. This includes everything from technical processes to administrative and business processes. (People usually think that a certain process can't be automated, but if you think a bit, there's always a way, so don't give up so easily, think outside the box).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure everything that can be measured&lt;/strong&gt;: Identify key performance indicators (KPIs) that can be measured and set up monitoring and reporting systems to do so (it doesn't have to be something extremely complex, it can even be with notes). This allows you to identify bottlenecks and areas for improvement in the company's processes and procedures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encourage collaboration and communication between teams&lt;/strong&gt;: Break down silos between teams and encourage collaboration and communication among them. This allows for a better understanding of the company's processes and procedures and makes it easier to identify areas for improvement. Just because something is automated doesn't mean communication between teams is lost; on the contrary, it should be more fluid and problem detection should be faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foster a culture of continuous improvement&lt;/strong&gt;: Create an environment that encourages continuous improvement and innovation. This includes everything from training and skill development to implementing new technologies and tools. Don't get stuck with what you already know; there's always something new to learn and improve. Especially in the automation process, there are always new tools and technologies that can make work easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Committed leadership&lt;/strong&gt;: It's essential that company leadership is committed to implementing the &lt;em&gt;DevOps&lt;/em&gt; culture. This includes everything from allocating resources to communicating the company's vision and objectives. If leadership is not committed, it's very likely that the implementation of the &lt;em&gt;DevOps&lt;/em&gt; culture will fail. It must be a mindset change throughout the company, and this is only achieved with committed and visionary leadership. If someone is not committed, it's better they are not in the company (it's a tough process, but many companies have failed by trying to keep those who don't want to change, and this only generates friction and resistance where change is needed).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these steps, it may be possible to implement the &lt;em&gt;DevOps&lt;/em&gt; culture in a company and be more efficient, but following a few steps is not everything: it's a continuous process that requires commitment and dedication from the entire company. That's why I want to dedicate a special section to the hardest part of this whole process: &lt;em&gt;The mindset change&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Understand that implementing the &lt;em&gt;DevOps&lt;/em&gt; culture in a company is not just a change of processes and procedures, it's a radical change of mindset. Many times, people and teams are used to working a certain way and may resist this change, especially those who have survived various company transformations, and it's understandable: change is scary, but it's necessary to be competitive in today's market. Some may think they will lose power, their job, or become obsolete, and that's understandable, but it's important to communicate that implementing the &lt;em&gt;DevOps&lt;/em&gt; culture is not about eliminating jobs, but about making them more efficient and productive. It's important to communicate that automation is not to eliminate jobs, but to eliminate repetitive and tedious tasks that add no value to the product or service being offered.&lt;/p&gt;

&lt;p&gt;In the end, what most companies want is to deliver a product, and many employees need to start understanding that what gives value to the company is the product or service being offered, not the processes and procedures used to do so. Many employees believe that by doing many things they are being productive, but just because you do a lot doesn't mean you're being productive; if those things don't add value to the product or service being offered, then they're not productive. So, you must change the mindset to focus on the product or service being offered, not the processes and procedures used to do so. Employees will no longer be tied to repetitive and tedious tasks, but will be focused on delivering a quality product or service, being much happier (due to less work) and more productive.&lt;/p&gt;

&lt;p&gt;Don't feel bad or be afraid of the resistance to change that may exist in your company. It's normal, and it's part of the process. Many other companies have experienced this resistance to change. A clear case was &lt;em&gt;Nokia&lt;/em&gt;, they had a very entrenched culture and established processes, and when they tried to implement the &lt;em&gt;DevOps&lt;/em&gt; culture, there was too much resistance, different departments fought each other for power, and decisions weren't made. In the end, the company couldn't adapt to change and was brutally overtaken by the competition. &lt;em&gt;Nokia&lt;/em&gt; is the clear example that it didn't fall because of its technology, it fell because of its culture and resistance to change.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It is not the strongest species that survives, nor the most intelligent, but the one that best responds to change" - Charles Darwin&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Thank you for reading this far. I hope this article has been useful and has given you a new perspective on implementing the &lt;em&gt;DevOps&lt;/em&gt; culture in a company, whether you are in a company that wants to implement it, or in a company that has already implemented it and wants to improve it. Remember that implementing the &lt;em&gt;DevOps&lt;/em&gt; culture is a continuous process that requires commitment and dedication from the entire company, but the benefits are enormous, from improved efficiency and productivity to improved quality of the product or service being offered.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Change is the only constant in life" - Heraclitus&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>devops</category>
      <category>startup</category>
    </item>
    <item>
      <title>Del Caos al Control: La Filosofía de Flutter BLoC para un Estado Predecible</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Thu, 12 Jun 2025 14:40:17 +0000</pubDate>
      <link>https://dev.to/sazardev/del-caos-al-control-la-filosofia-de-flutter-bloc-para-un-estado-predecible-40dh</link>
      <guid>https://dev.to/sazardev/del-caos-al-control-la-filosofia-de-flutter-bloc-para-un-estado-predecible-40dh</guid>
      <description>&lt;h2&gt;
  
  
  La Motivación: ¿Por Qué Nació BLoC?
&lt;/h2&gt;

&lt;p&gt;Imagina que estás construyendo una casa. La &lt;strong&gt;interfaz de usuario (UI)&lt;/strong&gt; son las paredes, los muebles, los cuadros; todo lo que ves y con lo que interactúas. La &lt;strong&gt;lógica de negocio&lt;/strong&gt; es la plomería, el sistema eléctrico, la calefacción; todo lo que hace que la casa funcione por detrás.&lt;/p&gt;

&lt;p&gt;En una aplicación pequeña, podrías tener los cables y las tuberías a la vista, mezclados con los muebles. Al principio no es un gran problema. Pero, ¿qué pasa cuando la casa se vuelve una mansión? Si un enchufe deja de funcionar, tendrías que romper paredes y mover muebles solo para encontrar el cable defectuoso. Si quieres cambiar la calefacción, podrías dañar el sistema de agua sin querer. &lt;strong&gt;Es un caos.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esto mismo sucedía en las primeras etapas de Flutter. Los desarrolladores a menudo mezclaban la lógica (qué hacer con los datos, cómo interactuar con una base de datos, etc.) directamente en los widgets de la UI. Esto provocaba varios problemas graves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Código Espagueti:&lt;/strong&gt; La lógica estaba tan entrelazada con la UI que era imposible saber dónde empezaba una y terminaba la otra.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Difícil de Testear:&lt;/strong&gt; ¿Cómo pruebas la lógica de un pago si está dentro de un botón? Tendrías que simular un clic en el botón en lugar de simplemente probar la función de "pagar".&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reutilización Imposible:&lt;/strong&gt; Si querías usar la misma lógica de "iniciar sesión" en otra parte de la app, tenías que copiar y pegar un montón de código de UI junto con la lógica.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Estado Inmanejable:&lt;/strong&gt; A medida que la app crecía, era increíblemente difícil saber por qué la pantalla se actualizaba o de dónde venían los datos que se mostraban.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;La solución era clara:&lt;/strong&gt; necesitábamos un arquitecto. Un patrón que nos obligara a instalar la plomería y la electricidad (la lógica) en una sala de máquinas central, completamente separada de las habitaciones (la UI).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aquí es donde nace BLoC.&lt;/strong&gt; Su motivación principal es &lt;strong&gt;imponer una separación estricta y clara entre la presentación (UI) y la lógica de negocio.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  La Filosofía y Lógica Central: El Flujo Reactivo
&lt;/h2&gt;

&lt;p&gt;La filosofía de BLoC se basa en una idea muy simple pero poderosa: &lt;strong&gt;La UI notifica al BLoC sobre eventos del usuario, y el BLoC notifica a la UI sobre cambios de estado.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pensemos en una analogía: &lt;strong&gt;una cafetería ☕.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tú (El Usuario):&lt;/strong&gt; Llegas al mostrador.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El Mostrador (La UI):&lt;/strong&gt; Es donde interactúas. Ves los botones: "Pedir Espresso", "Pedir Latte".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tu Pedido (El Evento):&lt;/strong&gt; Cuando presionas "Pedir Latte", creas un &lt;strong&gt;Evento&lt;/strong&gt;. El evento es una simple descripción de lo que quieres: &lt;code&gt;PedidoDeLatte&lt;/code&gt;. No preparas el café, solo comunicas tu intención.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El Barista (El BLoC):&lt;/strong&gt; El barista toma tu pedido (el Evento &lt;code&gt;PedidoDeLatte&lt;/code&gt;). Él es el único que sabe cómo preparar el café. Tiene la máquina, el conocimiento y los ingredientes. Esta es la &lt;strong&gt;lógica de negocio&lt;/strong&gt;. No hablas directamente con la máquina de café; hablas con el barista.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El Proceso (La Lógica dentro del BLoC):&lt;/strong&gt; El barista muele el grano, calienta la leche, extrae el espresso... realiza una serie de pasos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;La Pantalla de Pedidos (El Estado):&lt;/strong&gt; Mientras esperas, miras una pantalla. Primero dice &lt;code&gt;PedidoRecibido&lt;/code&gt;. Luego cambia a &lt;code&gt;PreparandoCafe&lt;/code&gt;. Finalmente, cambia a &lt;code&gt;PedidoListo(tuLatte)&lt;/code&gt;. Estos son los &lt;strong&gt;Estados&lt;/strong&gt;. El barista va actualizando esta pantalla para que sepas qué está pasando.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recoges tu Café (La UI Reacciona al Estado):&lt;/strong&gt; Cuando ves el estado &lt;code&gt;PedidoListo&lt;/code&gt;, tu parte de la UI (tu vista) se actualiza: ahora tienes un café en la mano.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esta es la esencia de BLoC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Eventos (Events):&lt;/strong&gt; Objetos inmutables que representan las intenciones del usuario o del sistema (ej: &lt;code&gt;BotonDeLoginPresionado&lt;/code&gt;, &lt;code&gt;DatosSolicitados&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BLoC (Business Logic Component):&lt;/strong&gt; La clase que recibe los Eventos, procesa la lógica correspondiente (hacer una llamada a una API, calcular algo) y emite nuevos Estados.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estados (States):&lt;/strong&gt; Objetos inmutables que representan una parte del estado de tu aplicación (ej: &lt;code&gt;Cargando&lt;/code&gt;, &lt;code&gt;Exitoso&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;). La UI simplemente escucha estos estados y se redibuja a sí misma según corresponda.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este flujo es &lt;strong&gt;reactivo y predecible&lt;/strong&gt;. La UI solo puede cambiar en respuesta a un nuevo estado emitido por el BLoC. Y el BLoC solo cambia su estado en respuesta a un evento. Sabes exactamente cómo fluye la información, lo que hace que depurar sea infinitamente más fácil.&lt;/p&gt;




&lt;h2&gt;
  
  
  ¿Qué Soluciona y Qué Hace Exactamente?
&lt;/h2&gt;

&lt;p&gt;BLoC soluciona el problema de la &lt;strong&gt;gestión del estado&lt;/strong&gt; de una manera escalable y organizada.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Centraliza tu lógica de negocio:&lt;/strong&gt; Todo el "cerebro" de una funcionalidad (autenticación, carrito de compras, perfil de usuario) vive en un solo lugar: su BLoC.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Desacopla la UI de la lógica:&lt;/strong&gt; Tu UI se vuelve "tonta". No sabe &lt;em&gt;cómo&lt;/em&gt; iniciar sesión, solo sabe que hay un estado &lt;code&gt;Cargando&lt;/code&gt; y debe mostrar un spinner, y un estado &lt;code&gt;Autenticado&lt;/code&gt; y debe navegar a la pantalla principal.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Facilita las pruebas:&lt;/strong&gt; Puedes probar tu lógica de inicio de sesión (el &lt;code&gt;AuthBloc&lt;/code&gt;) de forma aislada. Le das un evento &lt;code&gt;LoginEvent&lt;/code&gt; y verificas que emita los estados &lt;code&gt;LoadingState&lt;/code&gt; y luego &lt;code&gt;AuthenticatedState&lt;/code&gt;, todo sin renderizar un solo píxel en la pantalla.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Hace tu estado predecible:&lt;/strong&gt; Al restringir el flujo a &lt;code&gt;Evento -&amp;gt; BLoC -&amp;gt; Estado&lt;/code&gt;, siempre puedes rastrear por qué algo cambió. La librería &lt;code&gt;bloc&lt;/code&gt; incluso viene con un &lt;code&gt;BlocObserver&lt;/code&gt; que te permite imprimir cada transición de estado en la consola.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;¿Qué NO hace?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esto es igualmente importante para entenderlo bien.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;No realiza la inyección de dependencias:&lt;/strong&gt; BLoC no sabe cómo ser "provisto" a la UI. Para esto, se apoya en otra librería, &lt;code&gt;flutter_bloc&lt;/code&gt;, que usa &lt;code&gt;provider&lt;/code&gt; por debajo para inyectar eficientemente tus BLoCs en el árbol de widgets.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;No es un framework de navegación:&lt;/strong&gt; BLoC puede emitir un estado que &lt;em&gt;desencadene&lt;/em&gt; una navegación (usando un &lt;code&gt;BlocListener&lt;/code&gt;), pero la lógica de navegación en sí misma (usando &lt;code&gt;Navigator.push&lt;/code&gt; o &lt;code&gt;GoRouter&lt;/code&gt;) está fuera de su responsabilidad.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;No hace las llamadas a la API directamente:&lt;/strong&gt; Tu BLoC &lt;em&gt;orquestará&lt;/em&gt; la llamada, pero la implementación real de la llamada (el código que usa &lt;code&gt;http.get&lt;/code&gt; o &lt;code&gt;dio.get&lt;/code&gt;) debería estar en una capa separada, comúnmente llamada &lt;strong&gt;Repositorio&lt;/strong&gt; o &lt;strong&gt;Proveedor de Datos&lt;/strong&gt;. El BLoC llama al repositorio, y el repositorio obtiene los datos.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  ¿Cuándo Usarlo y Cuándo NO? (El Dilema del BLoC vs. Cubit)
&lt;/h2&gt;

&lt;p&gt;No necesitas un BLoC para todo. Usar BLoC para manejar el estado de un simple checkbox es como usar un tráiler para llevar una bolsa del supermercado.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cubit: El Hermano Menor y Simplificado
&lt;/h3&gt;

&lt;p&gt;El equipo de BLoC creó &lt;strong&gt;Cubit&lt;/strong&gt;, una versión más ligera y simple. La diferencia clave es:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BLoC:&lt;/strong&gt; Usa &lt;strong&gt;Eventos&lt;/strong&gt; (&lt;code&gt;add(LoginEvent())&lt;/code&gt;). Es más verboso pero más trazable. Sabes exactamente &lt;em&gt;qué&lt;/em&gt; causó el cambio de estado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cubit:&lt;/strong&gt; Expone &lt;strong&gt;funciones&lt;/strong&gt; públicas (&lt;code&gt;login()&lt;/code&gt;). Es más directo y requiere menos código.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analogía:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BLoC (El Restaurante Formal):&lt;/strong&gt; Das una orden formal (Evento) al mesero, y no sabes exactamente qué pasa en la cocina, solo esperas el resultado (Estado). Es bueno para procesos complejos y para tener un registro claro de cada orden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cubit (El Puesto de Tacos):&lt;/strong&gt; Le dices directamente al taquero: "¡Dame dos al pastor!" (llamas a una función &lt;code&gt;dameTacos(2)&lt;/code&gt;). Es rápido, directo y eficiente para tareas simples.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reglas de Oro:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Usa Cubit cuando:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La lógica es simple. Por ejemplo, manejar el tema de la app (oscuro/claro), controlar el índice de un &lt;code&gt;BottomNavigationBar&lt;/code&gt;, o manejar un formulario simple.&lt;/li&gt;
&lt;li&gt;Los cambios de estado son el resultado de llamadas a funciones directas, no de una cadena compleja de eventos.&lt;/li&gt;
&lt;li&gt;Quieres escribir menos código para una funcionalidad sencilla.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Usa BLoC cuando:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La lógica de negocio es &lt;strong&gt;compleja&lt;/strong&gt; y tiene múltiples pasos. Un proceso de pago, por ejemplo: &lt;code&gt;ValidarFormulario -&amp;gt; ProcesarPagoConAPI -&amp;gt; CrearOrdenEnBD -&amp;gt; EnviarEmailDeConfirmacion&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Necesitas &lt;strong&gt;trazabilidad&lt;/strong&gt;. Quieres saber la secuencia exacta de eventos que llevaron a un estado de error. Esto es invaluable para la depuración.&lt;/li&gt;
&lt;li&gt;Los eventos pueden venir de múltiples fuentes: clics del usuario, respuestas de un WebSocket, notificaciones push, etc.&lt;/li&gt;
&lt;li&gt;Estás trabajando en un equipo grande y quieres que la lógica sea explícita y fácil de entender para todos.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusión:&lt;/strong&gt; Empieza con un Cubit. Si tu lógica empieza a volverse compleja y te encuentras poniendo demasiada inteligencia dentro de una sola función, es una señal de que necesitas refactorizar a un BLoC para manejar esa complejidad con eventos más granulares.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rendimiento: ¿Cómo Evitar Reconstrucciones Innecesarias?
&lt;/h2&gt;

&lt;p&gt;Una preocupación común con cualquier gestor de estado es el rendimiento. ¿Se reconstruirá toda mi pantalla cada vez que cambie un pequeño detalle del estado? Con BLoC, la respuesta es &lt;strong&gt;no, si lo usas correctamente.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;La librería &lt;code&gt;flutter_bloc&lt;/code&gt; te da herramientas precisas para controlar qué se reconstruye y cuándo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;BlocBuilder&lt;/code&gt;:&lt;/strong&gt; Es el widget más común. Se reconstruye cada vez que el BLoC emite un &lt;strong&gt;nuevo&lt;/strong&gt; estado. Por defecto, es bastante inteligente y no se reconstruirá si el estado emitido es idéntico al anterior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;buildWhen&lt;/code&gt;:&lt;/strong&gt; Este es el superpoder de &lt;code&gt;BlocBuilder&lt;/code&gt;. Es una condición opcional que te permite especificar &lt;em&gt;exactamente&lt;/em&gt; cuándo debe reconstruirse el widget.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  * **Ejemplo:** En una pantalla de login, podrías tener un estado `LoginState` con propiedades `(email, password, status, errorMessage)`. Si el usuario solo está escribiendo en el campo de texto del email, no necesitas reconstruir el botón de login. Con `buildWhen`, puedes decirle que solo se reconstruya si el `status` (ej: `Loading`, `Success`, `Failure`) cambia.

&amp;lt;!-- end list --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```dart
BlocBuilder&amp;lt;LoginBloc, LoginState&amp;gt;(
  buildWhen: (previous, current) {
    // Solo reconstruye el widget si el estado de la petición cambia,
    // no si solo cambia el texto del email o la contraseña.
    return previous.status != current.status;
  },
  builder: (context, state) {
    // UI que muestra un spinner o un mensaje de error
    if (state.status == LoginStatus.loading) {
      return CircularProgressIndicator();
    }
    return ElevatedButton(onPressed: ..., child: Text('Login'));
  },
)
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;BlocSelector&lt;/code&gt;:&lt;/strong&gt; Es aún más granular. Te permite escuchar cambios en una &lt;strong&gt;pequeña parte&lt;/strong&gt; del estado.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  * **Ejemplo:** Imagina un `UserState` con `(name, age, profileImageUrl)`. Si solo quieres reconstruir el widget del nombre cuando el nombre cambie, `BlocSelector` es perfecto. Evita reconstruir el widget de la imagen de perfil innecesariamente.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;BlocListener&lt;/code&gt;:&lt;/strong&gt; Este widget es para &lt;strong&gt;efectos secundarios&lt;/strong&gt;. No reconstruye ninguna UI. Su propósito es ejecutar una acción una sola vez en respuesta a un cambio de estado.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  * **Usos perfectos:** Mostrar un `SnackBar` ("Usuario guardado con éxito"), un diálogo de error, o para la **navegación** (`Navigator.push(...)` cuando el estado sea `LoginSuccess`).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;Equatable&lt;/code&gt;:&lt;/strong&gt; Para que &lt;code&gt;buildWhen&lt;/code&gt; y el comportamiento por defecto de &lt;code&gt;BlocBuilder&lt;/code&gt; funcionen correctamente, tus objetos de estado deben poder compararse. La librería &lt;code&gt;equatable&lt;/code&gt; te ayuda a hacer esto fácilmente, simplemente listando las propiedades que definen la identidad del objeto.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  La Implementación Ideal: Paso a Paso
&lt;/h2&gt;

&lt;p&gt;Vamos a construir un ejemplo práctico: una pantalla que carga una lista de usuarios desde una API.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Estructura de Carpetas
&lt;/h3&gt;

&lt;p&gt;Una buena organización es clave. Para una funcionalidad de "usuarios", tendrías algo así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lib/
└── features/
    └── users/
        ├── bloc/
        │   ├── user_event.dart
        │   ├── user_state.dart
        │   └── user_bloc.dart
        ├── data/
        │   ├── user_repository.dart
        │   └── user_model.dart
        └── presentation/
            └── user_screen.dart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Definir los Estados (State)
&lt;/h3&gt;

&lt;p&gt;El estado representa todo lo que la UI necesita saber. ¿Qué estados puede tener nuestra pantalla de usuarios?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;UserInitial&lt;/code&gt;&lt;/strong&gt;: El estado inicial, antes de que hagamos nada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;UserLoading&lt;/code&gt;&lt;/strong&gt;: Estamos cargando los usuarios. La UI debería mostrar un spinner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;UserSuccess&lt;/code&gt;&lt;/strong&gt;: Tuvimos éxito. El estado contendrá la lista de usuarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;UserError&lt;/code&gt;&lt;/strong&gt;: Algo salió mal. El estado contendrá un mensaje de error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;user_state.dart&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;part of&lt;/span&gt; &lt;span class="s"&gt;'user_bloc.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Clase base abstracta para todos los estados&lt;/span&gt;
&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Equatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UserState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserInitial&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;UserState&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserLoading&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;UserState&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserSuccess&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;UserState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Los datos que la UI necesita&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UserSuccess&lt;/span&gt;&lt;span class="p"&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;users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserError&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;UserState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// El mensaje de error para la UI&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UserError&lt;/span&gt;&lt;span class="p"&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;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Definir los Eventos (Event)
&lt;/h3&gt;

&lt;p&gt;El evento es lo que la UI envía al BLoC para desencadenar una acción.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;FetchUsers&lt;/code&gt;&lt;/strong&gt;: Un evento para solicitar la carga de los usuarios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;user_event.dart&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;part of&lt;/span&gt; &lt;span class="s"&gt;'user_bloc.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserEvent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Equatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UserEvent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Único evento que necesitamos por ahora&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FetchUsers&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;UserEvent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Crear el BLoC
&lt;/h3&gt;

&lt;p&gt;Aquí es donde vive la magia. El BLoC escucha eventos y emite estados.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;user_bloc.dart&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:bloc/bloc.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:equatable/equatable.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Importamos nuestro repositorio y modelo&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'../data/user_model.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'../data/user_repository.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;part&lt;/span&gt; &lt;span class="s"&gt;'user_event.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;part&lt;/span&gt; &lt;span class="s"&gt;'user_state.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;UserBloc&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&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;userRepository&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserInitial&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Aquí registramos el manejador para nuestro evento&lt;/span&gt;
    &lt;span class="kd"&gt;on&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FetchUsers&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;_onFetchUsers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// El manejador de eventos es una función asíncrona&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_onFetchUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FetchUsers&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Emitter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Emitimos el estado de carga inmediatamente&lt;/span&gt;
    &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserLoading&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// 2. Llamamos al repositorio para obtener los datos&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// 3. Si todo va bien, emitimos el estado de éxito con los datos&lt;/span&gt;
      &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// 4. Si hay un error, emitimos el estado de error&lt;/span&gt;
      &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Failed to fetch users: &lt;/span&gt;&lt;span class="si"&gt;${e.toString()}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Observa la separación de responsabilidades: el BLoC no sabe *cómo&lt;/em&gt; se obtienen los usuarios (HTTP, base de datos...), solo llama a &lt;code&gt;userRepository.getUsers()&lt;/code&gt;. El repositorio es el que se encarga de eso.*&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Integrar con la UI
&lt;/h3&gt;

&lt;p&gt;Finalmente, conectamos todo en la pantalla.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;user_screen.dart&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_bloc/flutter_bloc.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Importamos todo lo necesario&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'../bloc/user_bloc.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'../data/user_repository.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersScreen&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UsersScreen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Users'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="c1"&gt;// 1. Proveemos el BLoC al árbol de widgets.&lt;/span&gt;
      &lt;span class="c1"&gt;// BlocProvider crea la instancia del BLoC y se asegura de cerrarla (dispose) correctamente.&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;BlocProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;create:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserBloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="c1"&gt;// Normalmente inyectarías el repositorio con get_it o provider&lt;/span&gt;
          &lt;span class="nl"&gt;userRepository:&lt;/span&gt; &lt;span class="n"&gt;RepositoryProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FetchUsers&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="c1"&gt;// Añadimos el evento inicial para que cargue los datos al entrar.&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UserView&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserView&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UserView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 2. Usamos BlocBuilder para escuchar los cambios de estado y construir la UI.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;BlocBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserBloc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 3. Renderizamos diferentes widgets basados en el estado actual.&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;UserLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CircularProgressIndicator&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;UserSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;itemCount:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;itemBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ListTile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nl"&gt;subtitle:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;UserError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Estado inicial o por defecto&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Press a button to fetch users.'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¡Y eso es todo! Hemos creado una funcionalidad robusta, testeable y desacoplada. La &lt;code&gt;UserView&lt;/code&gt; es completamente "tonta", simplemente refleja el estado que le da el &lt;code&gt;UserBloc&lt;/code&gt;. Si mañana necesitas cambiar la fuente de datos de una API REST a Firebase, solo modificas el &lt;code&gt;UserRepository&lt;/code&gt;, y ni el BLoC ni la UI se enterarán del cambio. &lt;strong&gt;Ese es el verdadero poder de BLoC.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>design</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>WebSockets Unplugged: A Developer's Guide to Real-Time Magic</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Wed, 11 Jun 2025 15:31:50 +0000</pubDate>
      <link>https://dev.to/sazardev/websockets-unplugged-a-developers-guide-to-real-time-magic-2b7p</link>
      <guid>https://dev.to/sazardev/websockets-unplugged-a-developers-guide-to-real-time-magic-2b7p</guid>
      <description>&lt;p&gt;Have you ever wondered how chat apps deliver messages instantly? Or how collaborative editing tools update in real-time? Behind this magic is a technology called WebSockets – and it's not as complicated as you might think!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Why HTTP Wasn't Enough
&lt;/h2&gt;

&lt;p&gt;Imagine you're at a restaurant (the browser) trying to talk to the kitchen (the server):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Traditional HTTP (REST API):&lt;/strong&gt; You ask the waiter a question, they go to the kitchen for an answer, return with a response, then leave. Every. Single. Time. Want to know if your food is ready? New waiter trip. Want to modify your order? Another waiter trip.&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%2Fuqfjbuppszfs2m7744d4.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%2Fuqfjbuppszfs2m7744d4.png" alt=" " width="569" height="964"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The HTTP Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each request needs a new connection&lt;/li&gt;
&lt;li&gt;The server can't talk to you unless you ask first&lt;/li&gt;
&lt;li&gt;Constantly asking "Is it ready yet?" wastes resources (polling)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Enter WebSockets: The Direct Phone Line
&lt;/h2&gt;

&lt;p&gt;WebSockets are like installing a direct phone line between you and the kitchen:&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%2Ffdtw4d1huwopmtil3qvk.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%2Ffdtw4d1huwopmtil3qvk.png" alt=" " width="625" height="793"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With WebSockets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You establish a connection ONCE&lt;/li&gt;
&lt;li&gt;Both sides can talk whenever they want&lt;/li&gt;
&lt;li&gt;The connection stays open until either side hangs up&lt;/li&gt;
&lt;li&gt;Messages flow freely in both directions&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How WebSockets Work: The Handshake Dance
&lt;/h2&gt;

&lt;p&gt;Let's break down how WebSockets actually connect:&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%2Fll50vzeornsu1ns86rmh.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%2Fll50vzeornsu1ns86rmh.png" alt=" " width="524" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's like going to a secret club:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You knock on the door (HTTP request)&lt;/li&gt;
&lt;li&gt;You whisper the secret password ("Upgrade: websocket")&lt;/li&gt;
&lt;li&gt;The bouncer checks your ID (handshake)&lt;/li&gt;
&lt;li&gt;Once inside, you're a member until you leave!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Real-World Analogies for WebSockets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Walkie-Talkie Analogy
&lt;/h3&gt;

&lt;p&gt;Traditional HTTP is like sending letters through mail. WebSockets are like walkie-talkies - always on, instant communication!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Party Line Analogy
&lt;/h3&gt;

&lt;p&gt;Remember old telephone party lines? WebSockets are similar - everyone on the line can hear and speak without hanging up and dialing again.&lt;/p&gt;

&lt;h3&gt;
  
  
  The News Subscription Analogy
&lt;/h3&gt;

&lt;p&gt;HTTP: Walking to the newsstand every 5 minutes to check for a new edition&lt;br&gt;
WebSockets: The newspaper being delivered the moment it's printed&lt;/p&gt;

&lt;h2&gt;
  
  
  When Would You Use WebSockets?
&lt;/h2&gt;

&lt;p&gt;Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat applications&lt;/li&gt;
&lt;li&gt;Live sports updates&lt;/li&gt;
&lt;li&gt;Collaborative editing tools&lt;/li&gt;
&lt;li&gt;Real-time dashboards&lt;/li&gt;
&lt;li&gt;Multiplayer games&lt;/li&gt;
&lt;li&gt;Stock tickers&lt;/li&gt;
&lt;li&gt;Notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not great for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple content websites&lt;/li&gt;
&lt;li&gt;Data that changes infrequently&lt;/li&gt;
&lt;li&gt;One-time data transfers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Typical WebSocket Scenario: The Chat App
&lt;/h2&gt;

&lt;p&gt;Here is how a basic chat app might use WebSockets:&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%2Fvjm4gnibuzafnlrvuwdz.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%2Fvjm4gnibuzafnlrvuwdz.png" alt=" " width="755" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The beauty is that Bob doesn't need to keep asking, "Did Alice send me a message?" The server pushes messages to Bob the moment Alice sends them!&lt;/p&gt;

&lt;h2&gt;
  
  
  What About WebSockets Under the Hood?
&lt;/h2&gt;

&lt;p&gt;Without getting too technical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initial handshake uses HTTP&lt;/li&gt;
&lt;li&gt;After upgrade, it's a different protocol (ws:// or wss://)&lt;/li&gt;
&lt;li&gt;Messages are framed differently than HTTP&lt;/li&gt;
&lt;li&gt;Can send text or binary data&lt;/li&gt;
&lt;li&gt;Includes built-in ping/pong to keep connections alive&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%2F3dl15nqya9k8twn3z7gb.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%2F3dl15nqya9k8twn3z7gb.png" alt=" " width="447" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of WebSockets
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency&lt;/strong&gt;: No need to send HTTP headers with every message&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: No connection setup/teardown overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time&lt;/strong&gt;: True bidirectional communication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less server load&lt;/strong&gt;: No polling with hundreds of requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better user experience&lt;/strong&gt;: Instant updates!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Practical Tips from a Developer's POV
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Secure WebSockets&lt;/strong&gt;: Always use &lt;code&gt;wss://&lt;/code&gt; (not &lt;code&gt;ws://&lt;/code&gt;) in production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle disconnections&lt;/strong&gt;: Networks are flaky, always implement reconnection logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be message-size aware&lt;/strong&gt;: Some proxies limit message sizes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider a fallback&lt;/strong&gt;: Some environments might block WebSockets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remember mobile&lt;/strong&gt;: Mobile connections can drop and reconnect often&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  So When Should You NOT Use WebSockets?
&lt;/h2&gt;

&lt;p&gt;WebSockets are not always the answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple websites&lt;/strong&gt;: Regular HTTP is simpler and more than adequate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RESTful services&lt;/strong&gt;: If you are just requesting data occasionally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When HTTP caching helps&lt;/strong&gt;: WebSockets bypass the HTTP caching system&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When you need simple horizontal scaling&lt;/strong&gt;: WebSockets maintain state, making scaling more complex&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;WebSockets bring the magic of real-time communication to the web. They solve the problem of bidirectional communication in an elegant way that allows for rich, interactive experiences.&lt;/p&gt;

&lt;p&gt;Next time you are building an app that needs instant updates or real-time interaction, remember our kitchen phone line! WebSockets might be exactly what you need to create that magical experience where things just happen instantly.&lt;/p&gt;

&lt;p&gt;Have you used WebSockets in your projects? What challenges did you face? Let's chat in the comments below!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Surviving Extreme Programming: A Developer's Wild Ride</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Tue, 10 Jun 2025 15:07:04 +0000</pubDate>
      <link>https://dev.to/sazardev/surviving-extreme-programming-a-developers-wild-ride-4m3a</link>
      <guid>https://dev.to/sazardev/surviving-extreme-programming-a-developers-wild-ride-4m3a</guid>
      <description>&lt;h1&gt;
  
  
  Surviving Extreme Programming: A Developer's Wild Ride
&lt;/h1&gt;

&lt;p&gt;Have you ever wanted to strap your coding practices to a rocket and send them to the moon? That is what Extreme Programming (XP) does to traditional software development. As a developer who has been through the XP wringer, I am here to tell you it is both terrifying and exhilarating - like riding a rollercoaster built by the same people who review your pull requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Heck is Extreme Programming Anyway?
&lt;/h2&gt;

&lt;p&gt;Extreme Programming is like regular programming, but after it's chugged five espressos. It takes good engineering practices and cranks them up to eleven.&lt;/p&gt;

&lt;p&gt;Think of it this way: If traditional development is like carefully planning a road trip with maps and hotel reservations, XP is more like deciding to drive cross-country with only a compass, a full tank of gas, and the willingness to change direction every time someone in the backseat spots something interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pair Programming: Two Keyboards, One Brain
&lt;/h2&gt;

&lt;p&gt;Imagine having someone watching over your shoulder while you code... ALL. THE. TIME. That's pair programming, and yes, it's as awkward as it sounds at first.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Real-life example: *&lt;/em&gt; Last month, I was pairing with Alex on a particularly nasty authentication bug. I was driving (typing), and Alex was navigating (directing).&lt;/p&gt;

&lt;p&gt;Me: &lt;em&gt;confidently typing&lt;/em&gt; "This should fix it."&lt;br&gt;
Alex: "You just created three new bugs in two lines of code."&lt;br&gt;
Me: "...talent."&lt;/p&gt;

&lt;p&gt;But here is the weird part - it works! After a few weeks of pair programming:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;My code quality improved dramatically&lt;/li&gt;
&lt;li&gt;I stopped making silly mistakes (goodbye, infinite loops!)&lt;/li&gt;
&lt;li&gt;I learned tricks I never would have discovered on my own&lt;/li&gt;
&lt;li&gt;My ability to explain my thinking improved &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is like having a real-time code review, brainstorming session, and therapy appointment all at once.&lt;/p&gt;
&lt;h2&gt;
  
  
  Test-Driven Development: Write Tests, Fail Tests, Question Life Choices
&lt;/h2&gt;

&lt;p&gt;TDD is like building a safety net before attempting a trapeze act. It feels like a waste of time until you're falling through the air screaming.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;In practice: *&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a test for a feature that does not exist yet&lt;/li&gt;
&lt;li&gt;Watch it fail (duh)&lt;/li&gt;
&lt;li&gt;Write just enough code to make it pass&lt;/li&gt;
&lt;li&gt;Refactor until it is not embarrassing&lt;/li&gt;
&lt;li&gt;Repeat until you have built something that works&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;*&lt;em&gt;Real-world example: *&lt;/em&gt; Our team was building a payment processing system. Instead of diving straight into code, we wrote tests for every scenario: successful payments, failed payments, expired cards, zombie apocalypse, etc.&lt;/p&gt;

&lt;p&gt;When we finally wrote the actual code, we discovered we had forgotten to manage timeouts. But guess what? Our test caught it before it ever hit production. No late-night emergency calls, no angry customers, no sad developers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Continuous Integration: Commit Early, Commit Often, Commit Therapy
&lt;/h2&gt;

&lt;p&gt;In XP, we commit code to the main branch multiple times a day. It is like ripping off a band-aid repeatedly until you get used to the pain.&lt;/p&gt;

&lt;p&gt;Before XP, my commits looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -m "Massive changes to everything after 2 weeks of work"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After XP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -m "Changed button color to blue"
git commit -m "Made button 2px wider"
git commit -m "Button now does the thing when clicked"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is like keeping your room clean by putting things away at once instead of waiting until your floor disappears under a pile of laundry and pizza boxes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Customer Is Always... Right There. Always.
&lt;/h2&gt;

&lt;p&gt;In XP, customers (or their representatives) are part of the team. They do not just drop requirements from the mountaintop and disappear - they are right there in the trenches with you.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Example: *&lt;/em&gt; We were building a dashboard for financial analysts. Instead of guessing what they needed, we had Sarah from the finance team sitting with us three days a week.&lt;/p&gt;

&lt;p&gt;Me: "Would you prefer the reports in a table or chart format?"&lt;br&gt;
Sarah: "Actually, can we have both with a toggle switch?"&lt;br&gt;
Me: &lt;em&gt;thinking&lt;/em&gt; "That's... actually a great idea I never would have thought of."&lt;/p&gt;

&lt;p&gt;It's like cooking dinner with someone instead of trying to guess what they want to eat.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Velocity Paradox: Going Slow to Go Fast
&lt;/h2&gt;

&lt;p&gt;XP feels slower at first. Writing tests takes time. Pairing takes time. Planning takes time. It is like packing properly for a trip instead of just throwing random stuff in a suitcase and hoping for the best.&lt;/p&gt;

&lt;p&gt;But then something magical happens - you stop wasting time on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixing bugs that could have been prevented&lt;/li&gt;
&lt;li&gt;Building features nobody wants&lt;/li&gt;
&lt;li&gt;Massive refactoring because the code became unmaintainable&lt;/li&gt;
&lt;li&gt;Emergency hotfixes at 2 AM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;*&lt;em&gt;Personal story: *&lt;/em&gt; Our team spent an entire sprint refactoring and adding tests to a legacy module. Management was nervous about the "lack of new features." Three months later, every other team was still putting out fires while we were consistently delivering new features every week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is XP Right for You? A Handy Quiz
&lt;/h2&gt;

&lt;p&gt;You might enjoy Extreme Programming if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You like feedback faster than your morning coffee can cool&lt;/li&gt;
&lt;li&gt;The idea of fewer bugs makes you unreasonably happy&lt;/li&gt;
&lt;li&gt;You're willing to be humbled daily in exchange for becoming a better developer&lt;/li&gt;
&lt;li&gt;You prefer short, focused work sessions over heroic all-nighters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might NOT enjoy Extreme Programming if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You prefer coding in isolation like a wizard in a tower&lt;/li&gt;
&lt;li&gt;You think tests are for people who write bad code&lt;/li&gt;
&lt;li&gt;You enjoy the adrenaline rush of deploying untested code to production&lt;/li&gt;
&lt;li&gt;The phrase "let's pair on this" sends shivers down your spine&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The XP Developer Survival Kit
&lt;/h2&gt;

&lt;p&gt;If you're about to dive into an XP project, here is what you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A thick skin&lt;/strong&gt; - Your code will be reviewed constantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An open mind&lt;/strong&gt; - Some practices will feel weird before they feel right&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comfortable headphones&lt;/strong&gt; - For when you need a break from pairing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The ability to say "I don't know"&lt;/strong&gt; - XP values honesty over heroics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A sense of humor&lt;/strong&gt; - Because sometimes your tests will fail in spectacular ways&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion: The Extremely Good Parts
&lt;/h2&gt;

&lt;p&gt;After years of practicing XP, I cannot imagine going back. Yes, it is extreme. Yes, it can be uncomfortable. But it is also incredibly effective.&lt;/p&gt;

&lt;p&gt;Have you tried Extreme Programming practices in your work? Which ones worked for you and which ones didn't? Let me know in the comments!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>agile</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why Developers Are Just Doctors for Computers</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Mon, 09 Jun 2025 12:43:48 +0000</pubDate>
      <link>https://dev.to/sazardev/why-developers-are-just-doctors-for-computers-o8c</link>
      <guid>https://dev.to/sazardev/why-developers-are-just-doctors-for-computers-o8c</guid>
      <description>&lt;p&gt;&lt;em&gt;Ever wondered why your dev friend always looks so tired? They're basically running a 24/7 emergency room for code.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Similarities Are Uncanny 🤔
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Debugging = Medical Diagnosis&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Developer:&lt;/strong&gt; "Hmm, the app is crashing. Let me check the logs..."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doctor:&lt;/strong&gt; "Hmm, you have a fever. Let me run some tests..."&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Both involve a lot of &lt;code&gt;console.log()&lt;/code&gt; statements and "turn it off and on again"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Code Reviews = Second Opinions&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Developer:&lt;/strong&gt; "Can you look at my PR? Something feels off..."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doctor:&lt;/strong&gt; "Can you review this case? Something doesn't add up..."&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Both can save lives (or at least save you from production disasters)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Stack Traces = Medical Records&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Long, confusing, full of technical jargon&lt;/li&gt;
&lt;li&gt;Only make sense to professionals&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Patients/Users: "Can you explain this in English?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Hotfixes = Emergency Surgery&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;High pressure&lt;/li&gt;
&lt;li&gt;No room for mistakes&lt;/li&gt;
&lt;li&gt;Everyone's watching&lt;/li&gt;
&lt;li&gt;Coffee is your best friend ☕&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Diagnosis Process 🔍
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Patient/App shows symptoms
2. Ask questions nobody understands
3. Run mysterious tests
4. Stare at results for 20 minutes
5. Try the simplest solution first
6. If that fails, Google it
7. Blame it on lifestyle choices/user error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common "Diseases" We Treat
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Computer Disease&lt;/th&gt;
&lt;th&gt;Human Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory leak&lt;/td&gt;
&lt;td&gt;Chronic fatigue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infinite loop&lt;/td&gt;
&lt;td&gt;Insomnia&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;404 Error&lt;/td&gt;
&lt;td&gt;Amnesia&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buffer overflow&lt;/td&gt;
&lt;td&gt;Indigestion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Race condition&lt;/td&gt;
&lt;td&gt;Multiple personality disorder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deadlock&lt;/td&gt;
&lt;td&gt;Paralysis&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Famous Last Words 💀
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Doctors:&lt;/strong&gt; &lt;em&gt;"This won't hurt a bit"&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Developers:&lt;/strong&gt; &lt;em&gt;"This should work in production"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Both are usually wrong.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bedside Manner
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Doctor:&lt;/strong&gt; "Take two aspirin and call me in the morning"&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Developer:&lt;/strong&gt; "Clear your cache and restart your browser"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Patient:&lt;/strong&gt; "But I already tried that..."&lt;br&gt;&lt;br&gt;
&lt;strong&gt;User:&lt;/strong&gt; "But I already tried that..."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Both:&lt;/strong&gt; "Try it again." 🤷‍♂️&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Truth
&lt;/h2&gt;

&lt;p&gt;At 3 AM, both are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drinking way too much caffeine&lt;/li&gt;
&lt;li&gt;Questioning their life choices&lt;/li&gt;
&lt;li&gt;Saving someone's day/life&lt;/li&gt;
&lt;li&gt;Wondering why they didn't become accountants&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Remember: Always listen to your developer. They know when your system needs rest, updates, or a complete reboot. Just like doctors, but with less malpractice insurance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What other job analogies describe developers perfectly? Drop them in the comments! 👇&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;*Posted by &lt;a class="mentioned-user" href="https://dev.to/sazardev"&gt;@sazardev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>developer</category>
      <category>humor</category>
      <category>programming</category>
      <category>coding</category>
    </item>
    <item>
      <title>I made a project in Golang with no packages or libraries (also not ORM's)</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Fri, 11 Apr 2025 18:44:15 +0000</pubDate>
      <link>https://dev.to/sazardev/i-made-a-project-in-golang-with-no-packages-or-libraries-also-not-orms-15fa</link>
      <guid>https://dev.to/sazardev/i-made-a-project-in-golang-with-no-packages-or-libraries-also-not-orms-15fa</guid>
      <description>&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;Okay, may you are asking yourself, why you do a project in Golang with no packages or libraries? First, the project requires an highly optimized database, high concurrency and a lot of performance, a lot of files and a lot of data. So, I thought, why not do it in Golang?&lt;/p&gt;

&lt;p&gt;The project it is about to make a conciliation with a different types of invoices reading &lt;code&gt;XML&lt;/code&gt; in two differents ways. First, it is using an API (easy) the second it's in a dynamic database location (hard). The two ways give me only &lt;code&gt;XML&lt;/code&gt; files, so I need to parse them and make a conciliation with the data. Also, when I get the conciliated invoices, that concilitation needs to be saved in a database. So, I need to make a lot of queries and a lot of data manipulation, and the hardest part is to make all this in a high performance way, when the data is conciliated the user will be able to sort and filter in the data.&lt;/p&gt;

&lt;h1&gt;
  
  
  The solution
&lt;/h1&gt;

&lt;p&gt;That is the problem. Using &lt;code&gt;Go&lt;/code&gt; was the best decission for this project, but why no packages? Not easy answer here, but I need to have a FULL control of the database, the querys, indexes, tables, and all the data. Even I need to control the database configuration. &lt;code&gt;GORM&lt;/code&gt; do not let me to customize every aspect of a table or column.&lt;/p&gt;

&lt;p&gt;Then another problem is a high concurrency with the two ways of getting data in different sources (And compress the &lt;code&gt;XML&lt;/code&gt; because it is a HUGE amount of data) and then parse it. So, I need to make a lot of goroutines and channels to make the data flow.&lt;/p&gt;

&lt;p&gt;Every pieces are on the table. Next lets see the structure project!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;|-- src
| |-- config
| |-- controller
| |-- database
| |-- handlers
| |-- interfaces
| |-- middleware
| |-- models
| |-- routes
| |-- services
| |-- utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Very simple, but very effective. I have a &lt;code&gt;config&lt;/code&gt; folder to store all the configuration of the project, like the database connection, the API keys, etc. The &lt;code&gt;controller&lt;/code&gt; folder as a bussiness logic headers, the &lt;code&gt;database&lt;/code&gt; folder as the database connection and the queries, the &lt;code&gt;handlers&lt;/code&gt; folder as the HTTP handlers, the &lt;code&gt;interfaces&lt;/code&gt; folder as the interfaces declared for the petitions in others APIs, the &lt;code&gt;middleware&lt;/code&gt; folder for CORS and , the &lt;code&gt;models&lt;/code&gt; folder as the models for the database, the &lt;code&gt;routes&lt;/code&gt; folder as the routes of the project, the &lt;code&gt;services&lt;/code&gt; folder as the services of the project and finally the &lt;code&gt;utils&lt;/code&gt; folder as a utility functions.&lt;/p&gt;

&lt;h1&gt;
  
  
  How the data is managed
&lt;/h1&gt;

&lt;p&gt;Now, lets talk about my database configuration, but please, keep in mind, that this configuration only works in MY situation, and this is the best only in this case, may not be useful in another cases. And visualize that every table has indexes.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;listen_addresses = '*'&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Configures which IP addresses PostgreSQL listens on. Setting this to &lt;code&gt;'*'&lt;/code&gt; allows connections from any IP address, making the database accessible from any network interface. Useful for servers that need to accept connections from multiple clients on different networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;shared_buffers = 256MB&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Determines the amount of memory dedicated to PostgreSQL for caching data. This is one of the most important parameters for performance, as it caches frequently accessed tables and indexes in RAM. 256MB is a moderate value that balances memory usage with improved query performance. For high-performance systems, this could be set to 25% of total system memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;work_mem = 16MB&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Specifies the memory allocated for sort operations and hash tables. Each query operation can use this amount of memory, so 16MB provides a reasonable balance. Setting this too high could lead to memory pressure if many queries run concurrently, while setting it too low forces PostgreSQL to use disk-based sorting.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;maintenance_work_mem = 128MB&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Defines memory dedicated to maintenance operations like VACUUM, CREATE INDEX, or ALTER TABLE. Higher values (like 128MB) accelerate these operations, especially on larger tables. This memory is only used during maintenance tasks, so it can safely be set higher than &lt;code&gt;work_mem&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;wal_buffers = 16MB&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Controls the size of the buffer for Write-Ahead Log (WAL) data before writing to disk. 16MB is sufficient for most workloads and helps reduce I/O pressure by batching WAL writes.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;synchronous_commit = off&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Disables waiting for WAL writes to be confirmed as written to disk before reporting success to clients. This dramatically improves performance by allowing the server to continue processing transactions immediately, at the cost of a small risk of data loss in case of system failure (typically just a few recent transactions).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;checkpoint_timeout = 15min&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Sets the maximum time between automatic WAL checkpoints. A longer interval (15 minutes) reduces I/O load by spacing out checkpoint operations but may increase recovery time after a crash.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;max_wal_size = 1GB&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Defines the maximum size of WAL files before triggering a checkpoint. 1GB allows for efficient handling of large transaction volumes before forcing a disk write.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;min_wal_size = 80MB&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Sets the minimum size to shrink the WAL to during checkpoint operations. Keeping at least 80MB prevents excessive recycling of WAL files, which would cause unnecessary I/O.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;random_page_cost = 1.1&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;An estimate of the cost of fetching a non-sequential disk page. The low value of 1.1 (close to 1.0) indicates the system is using SSDs or has excellent disk caching. This guides the query planner to prefer index scans over sequential scans.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;effective_cache_size = 512MB&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Tells the query planner how much memory is available for disk caching by the OS and PostgreSQL. 512MB indicates a moderate amount of system memory available for caching, influencing the planner to favor index scans.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;max_connections = 100&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Limits the number of simultaneous client connections. 100 connections is suitable for applications with moderate concurrency requirements while preventing resource exhaustion.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;max_worker_processes = 4&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Sets the maximum number of background worker processes the system can support. 4 workers allows parallel operations while preventing CPU oversubscription on smaller systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;max_parallel_workers_per_gather = 2&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Defines how many worker processes a single Gather operation can launch. Setting this to 2 enables moderate parallelism for individual queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;max_parallel_workers = 4&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Limits the total number of parallel workers that can be active at once. Matching this with &lt;code&gt;max_worker_processes&lt;/code&gt; ensures all worker slots can be used for parallelism if needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;log_min_duration_statement = 200&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Logs any query that runs longer than 200 milliseconds. This helps identify slow-performing queries that might need optimization, while not logging faster queries that would create excessive log volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table declarations
&lt;/h2&gt;

&lt;p&gt;Obviusly I will not put here every table created and every column (Also the names are changed) but this is a general idea.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;reconciliation&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;requester_id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;request_uuid&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;company_id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_reconciliation_request_uuid&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;reconciliation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_uuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_reconciliation_requester_id&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;reconciliation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requester_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_reconciliation_company_id&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;reconciliation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;reconciliation_invoice&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- Imagine 30 columns declarations...&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reconciliation_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;reconciliation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_reconciliation_invoice_reconciliation_id&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;reconciliation_invoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reconciliation_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_reconciliation_invoice_source_uuid&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;reconciliation_invoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source_system_uuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_reconciliation_invoice_erp_uuid&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;reconciliation_invoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;erp_system_uuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_reconciliation_invoice_reconciled&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;reconciliation_invoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reconciled&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;reconciliation_stats&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;reconciliation_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;reconciliation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- ... A lot of more stats props&lt;/span&gt;
    &lt;span class="n"&gt;document_type_stats&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;total_distribution&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_reconciliation_stats_reconciliation_id&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;reconciliation_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reconciliation_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Index Explanations
&lt;/h3&gt;

&lt;p&gt;The schema includes several strategic indexes to optimize query performance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Primary Key Indexes&lt;/strong&gt;: Each table has a primary key that automatically creates an index for fast record retrieval by ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Foreign Key Indexes&lt;/strong&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;idx_reconciliation_invoice_reconciliation_id&lt;/code&gt; enables efficient joins between reconciliation and invoice tables&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;idx_reconciliation_stats_reconciliation_id&lt;/code&gt; optimizes queries joining stats to their parent reconciliation&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lookup Indexes&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;idx_reconciliation_request_uuid&lt;/code&gt; for fast lookups by unique request identifier&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;idx_reconciliation_requester_id&lt;/code&gt; and &lt;code&gt;idx_reconciliation_company_id&lt;/code&gt; optimize filtering by company or requester&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Business Logic Indexes&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;idx_reconciliation_invoice_source_uuid&lt;/code&gt; and &lt;code&gt;idx_reconciliation_invoice_erp_uuid&lt;/code&gt; improve performance when matching documents between systems&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;idx_reconciliation_invoice_reconciled&lt;/code&gt; optimizes filtering by reconciliation status, which is likely a common query pattern&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These indexes significantly improve performance for the typical query patterns in a reconciliation system, where you often need to filter by company, requester, or match status, while potentially handling large volumes of invoice data.&lt;/p&gt;

&lt;h1&gt;
  
  
  How I handle the XML
&lt;/h1&gt;

&lt;p&gt;The KEY of why use &lt;code&gt;Go&lt;/code&gt; it was by how EASY is to use &lt;code&gt;XML&lt;/code&gt; in &lt;code&gt;Go&lt;/code&gt; (I am really in love and save HOURS). Maybe you never see an &lt;code&gt;XML&lt;/code&gt;, this is a fake example of an &lt;code&gt;XML&lt;/code&gt; invoice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Invoice&lt;/span&gt; &lt;span class="na"&gt;xmlns:qdt=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2"&lt;/span&gt;
&lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;&amp;lt;/cac:OrderReference&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:AccountingSupplierParty&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/cac:AccountingSupplierParty&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:AccountingCustomerParty&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/cac:AccountingCustomerParty&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:Delivery&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/cac:Delivery&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:PaymentMeans&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/cac:PaymentMeans&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:PaymentTerms&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/cac:PaymentTerms&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:AllowanceCharge&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/cac:AllowanceCharge&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:TaxTotal&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cbc:TaxAmount&lt;/span&gt; &lt;span class="na"&gt;currencyID=&lt;/span&gt;&lt;span class="s"&gt;"GBP"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;17.50&lt;span class="nt"&gt;&amp;lt;/cbc:TaxAmount&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cbc:TaxEvidenceIndicator&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/cbc:TaxEvidenceIndicator&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:TaxSubtotal&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cbc:TaxableAmount&lt;/span&gt; &lt;span class="na"&gt;currencyID=&lt;/span&gt;&lt;span class="s"&gt;"GBP"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;100.00&lt;span class="nt"&gt;&amp;lt;/cbc:TaxableAmount&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cbc:TaxAmount&lt;/span&gt; &lt;span class="na"&gt;currencyID=&lt;/span&gt;&lt;span class="s"&gt;"GBP"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;17.50&lt;span class="nt"&gt;&amp;lt;/cbc:TaxAmount&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:TaxCategory&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cbc:ID&amp;gt;&lt;/span&gt;A&lt;span class="nt"&gt;&amp;lt;/cbc:ID&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:TaxScheme&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cbc:ID&amp;gt;&lt;/span&gt;UK VAT&lt;span class="nt"&gt;&amp;lt;/cbc:ID&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cbc:TaxTypeCode&amp;gt;&lt;/span&gt;VAT&lt;span class="nt"&gt;&amp;lt;/cbc:TaxTypeCode&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cac:TaxScheme&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cac:TaxCategory&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cac:TaxSubtotal&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cac:TaxTotal&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:LegalMonetaryTotal&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/cac:LegalMonetaryTotal&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;cac:InvoiceLine&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;/cac:InvoiceLine&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Invoice&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In another language may can be PAINFUL to extract this data and more when the data have a child in a child in a child...&lt;/p&gt;

&lt;p&gt;This is an interface example in &lt;code&gt;Go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Invoice&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ID&lt;/span&gt;              &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"ID"`&lt;/span&gt;
    &lt;span class="n"&gt;IssueDate&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"IssueDate"`&lt;/span&gt;
    &lt;span class="n"&gt;SupplierParty&lt;/span&gt;   &lt;span class="n"&gt;Party&lt;/span&gt;  &lt;span class="s"&gt;`xml:"AccountingSupplierParty"`&lt;/span&gt;
    &lt;span class="n"&gt;CustomerParty&lt;/span&gt;   &lt;span class="n"&gt;Party&lt;/span&gt;  &lt;span class="s"&gt;`xml:"AccountingCustomerParty"`&lt;/span&gt;
    &lt;span class="n"&gt;TaxTotal&lt;/span&gt;        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;TaxAmount&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt;      &lt;span class="s"&gt;`xml:"TaxAmount"`&lt;/span&gt;
        &lt;span class="n"&gt;EvidenceIndicator&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;        &lt;span class="s"&gt;`xml:"TaxEvidenceIndicator"`&lt;/span&gt;
        &lt;span class="c"&gt;// Handling deeply nested elements&lt;/span&gt;
        &lt;span class="n"&gt;Subtotals&lt;/span&gt;         &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;TaxableAmount&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"TaxableAmount"`&lt;/span&gt;
            &lt;span class="n"&gt;TaxAmount&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"TaxAmount"`&lt;/span&gt;
            &lt;span class="c"&gt;// Even deeper nesting&lt;/span&gt;
            &lt;span class="n"&gt;Category&lt;/span&gt;      &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ID&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"ID"`&lt;/span&gt;
                &lt;span class="n"&gt;Scheme&lt;/span&gt;    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;ID&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"ID"`&lt;/span&gt;
                    &lt;span class="n"&gt;TypeCode&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"TaxTypeCode"`&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`xml:"TaxScheme"`&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`xml:"TaxCategory"`&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`xml:"TaxSubtotal"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`xml:"TaxTotal"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Party&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"Party&amp;gt;PartyName&amp;gt;Name"`&lt;/span&gt;
    &lt;span class="n"&gt;TaxID&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`xml:"Party&amp;gt;PartyTaxScheme&amp;gt;CompanyID"`&lt;/span&gt;
    &lt;span class="c"&gt;// Other fields omitted...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Very easy, right? With an interface we got everything ready to work extracting data and save from our APIs!&lt;/p&gt;

&lt;h1&gt;
  
  
  Concurrency
&lt;/h1&gt;

&lt;p&gt;Another aspect of why go for &lt;code&gt;Go&lt;/code&gt; is the concurrency. Why this project needs concurrency? Okay, lets see a diagram of how the data flow:&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%2Fcp9eggiz8wbmc1x06ai1.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%2Fcp9eggiz8wbmc1x06ai1.png" alt=" " width="177" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine, if I process every package one by one, I will be waiting a lot of time to process all the data. So, its the perfect time to use goroutines and channels.&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%2F7atnxops54vj10zeyby1.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%2F7atnxops54vj10zeyby1.png" alt=" " width="209" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;After completing this project with pure Go and no external dependencies, I can confidently say this approach was the right choice for this specific use case. The standard library proved to be remarkably capable, handling everything from complex XML parsing to high-throughput database operations.&lt;/p&gt;

&lt;p&gt;The key advantages I gained were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complete control over performance optimization&lt;/strong&gt; - By writing raw SQL queries and fine-tuning PostgreSQL configuration, I achieved performance levels that would be difficult with an ORM's abstractions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No dependency management headaches&lt;/strong&gt; - Zero external packages meant no version conflicts, security vulnerabilities from third-party code, or unexpected breaking changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Smaller binary size and reduced overhead&lt;/strong&gt; - The resulting application was lean and efficient, with no unused code from large libraries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deep understanding of the system&lt;/strong&gt; - Building everything from scratch forced me to understand each component thoroughly, making debugging and optimization much easier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Perfect fit for Go's strengths&lt;/strong&gt; - This approach leveraged Go's strongest features: concurrency with goroutines/channels, efficient XML handling, and a powerful standard library.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That said, this isn't the right approach for every project. The development time was longer than it would have been with established libraries and frameworks. For simpler applications or rapid prototyping, the convenience of packages like GORM or Echo would likely outweigh the benefits of going dependency-free.&lt;/p&gt;

&lt;p&gt;However, for systems with strict performance requirements handling large volumes of data with complex processing needs, the control offered by this bare-bones approach proved invaluable. The reconciliation system now processes millions of invoices efficiently, with predictable performance characteristics and complete visibility into every aspect of its operation.&lt;/p&gt;

&lt;p&gt;In the end, the most important lesson was knowing when to embrace libraries and when to rely on Go's powerful standard library - a decision that should always be driven by the specific requirements of your project rather than dogmatic principles about dependencies.&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>diy</category>
      <category>database</category>
    </item>
    <item>
      <title>Is bad learning new programming languages?</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Mon, 30 Sep 2024 22:20:27 +0000</pubDate>
      <link>https://dev.to/sazardev/is-bad-learning-new-programming-languages-1jma</link>
      <guid>https://dev.to/sazardev/is-bad-learning-new-programming-languages-1jma</guid>
      <description>&lt;p&gt;When I was in &lt;em&gt;high school&lt;/em&gt;, my teacher says that is truly &lt;strong&gt;unnecessary&lt;/strong&gt; to learn new &lt;em&gt;programming languages&lt;/em&gt;, because is better to be perfet in one language than to be average in many, and some other people think that this is a true fact, but for all that people that think that, I just can say that they are wrong.&lt;/p&gt;

&lt;p&gt;Wrong in the sens that learning new &lt;em&gt;programming languages&lt;/em&gt; is not just about learning a new syntax, is about learning a new way to think, a new way to solve problems, a new way to create things. It's about expanding your horizons, broadening your perspective, challenging your assumptions. It's about pushing yourself out of your comfort zone, stretching your limits, growing beyond your boundaries.&lt;/p&gt;

&lt;p&gt;Also, if you're work requires &lt;strong&gt;Java&lt;/strong&gt;, and you only know &lt;strong&gt;Java&lt;/strong&gt;, you're limiting yourself to &lt;strong&gt;Java&lt;/strong&gt; jobs, &lt;strong&gt;Java&lt;/strong&gt; projects, &lt;strong&gt;Java&lt;/strong&gt; opportunities. But if you know &lt;strong&gt;Java&lt;/strong&gt;, &lt;strong&gt;Python&lt;/strong&gt;, &lt;strong&gt;JavaScript&lt;/strong&gt;, &lt;strong&gt;C++&lt;/strong&gt;, you're opening yourself up to a world of possibilities, a world of opportunities, a world of challenges. You're making yourself more marketable, more versatile, more valuable. You're giving yourself the freedom to choose, the power to change, the confidence to succeed.&lt;/p&gt;

&lt;p&gt;So, is bad learning new &lt;em&gt;programming languages&lt;/em&gt;? No, it's not bad, it's good. I amply recommend to learn new &lt;em&gt;programming languages&lt;/em&gt;, because it will make you a better developer, also in the book "The Pragmatic Programmer" says that you should learn at least one new programming language every year, and I think that's a good advice, because maybe you'll never use that language in your work but you can learn to think different, build different.&lt;/p&gt;

&lt;p&gt;When I was using &lt;strong&gt;Flutter&lt;/strong&gt; two years ago, I was so closed to use only &lt;strong&gt;Provider&lt;/strong&gt; because is the most MVC pattern that I know, but then I learned &lt;strong&gt;React&lt;/strong&gt;, with his hooks, and I was amazed by how easy is to use it, and how powerful is to use it, also a really easy to view and control the state, then when i check &lt;strong&gt;Riverpod&lt;/strong&gt; in &lt;strong&gt;Flutter&lt;/strong&gt; is like a mix of both, and I was so happy to learn it, because I can use the best of both worlds.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The only way to learn a new programming language is by writing programs in it." - Dennis Ritchie&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>devjournal</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Provider en React con JavaScript</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Tue, 10 Sep 2024 21:47:04 +0000</pubDate>
      <link>https://dev.to/sazardev/provider-en-react-con-javascri-2nip</link>
      <guid>https://dev.to/sazardev/provider-en-react-con-javascri-2nip</guid>
      <description>&lt;p&gt;El patrón de comportamiento &lt;strong&gt;Provider&lt;/strong&gt; es un patrón de diseño que se utiliza para proporcionar datos a otros componentes. Donde la idea principal es que un componente padre proporcione datos a sus componentes hijos a traves de un arbol de componentes e inyectar dependencias a los componentes hijos de otros &lt;strong&gt;Providers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider&lt;/strong&gt; es además aquel encargado de &lt;em&gt;crear&lt;/em&gt;, &lt;em&gt;almacenar&lt;/em&gt; y &lt;em&gt;proporcionar&lt;/em&gt; los datos a los componentes hijos, donde la procedencia de esta información puede ser de una API, un archivo JSON, una base de datos, etc. Para un &lt;strong&gt;Provider&lt;/strong&gt; le es indistinto la procedencia de la información, y es algo que no debe importarle, solo debe manejarla y asegurarse de que la información recibida sea la solicitada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Componentes iniciales
&lt;/h2&gt;

&lt;p&gt;Para la creación de un &lt;strong&gt;Provider&lt;/strong&gt; se requiere plantear su estructura antes de utilizarlo, donde se necesita definir, a que &lt;strong&gt;&lt;em&gt;modulo&lt;/em&gt;&lt;/strong&gt; pertenece, con qué &lt;strong&gt;&lt;em&gt;información&lt;/em&gt;&lt;/strong&gt; se va a trabajar, y que &lt;strong&gt;&lt;em&gt;funciones&lt;/em&gt;&lt;/strong&gt; se van a utilizar para manipular la información. Por ende, necesitamos previamente un &lt;strong&gt;&lt;em&gt;servicio&lt;/em&gt;&lt;/strong&gt; que contenga comunicacion con la información, y un &lt;strong&gt;&lt;em&gt;modelo&lt;/em&gt;&lt;/strong&gt; que nos permita manipular la información.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crear un Provider en React con JavaScript
&lt;/h2&gt;

&lt;p&gt;Para crear un &lt;strong&gt;Provider&lt;/strong&gt; escalable, mantenible y reutilizable, se debe seguir una estructura que permita la manipulación de la información de manera eficiente. Para &lt;strong&gt;React&lt;/strong&gt; con JavaScript, es necesario crear alrededor de &lt;strong&gt;cinco archivos&lt;/strong&gt;, donde estos comprenden: &lt;strong&gt;&lt;em&gt;Contexto Global&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;Acciones&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;Reducer&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;Provider&lt;/em&gt;&lt;/strong&gt; y &lt;strong&gt;&lt;em&gt;Estado Inicial&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estado Inicial
&lt;/h3&gt;

&lt;p&gt;El &lt;strong&gt;Estado Inicial&lt;/strong&gt; es el encargado de almacenar la información que se va a utilizar en los componentes hijos, y se encarga de proporcionar la información a los componentes hijos. Para crear un &lt;strong&gt;Estado Inicial&lt;/strong&gt; se debe utilizar la siguiente estructura:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GlobalState.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GlobalState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Informacion inicial&lt;/span&gt;
  &lt;span class="c1"&gt;// Aqui se extrae tambien la informacion local&lt;/span&gt;
  &lt;span class="na"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;usuario&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Contexto Global
&lt;/h3&gt;

&lt;p&gt;El &lt;strong&gt;Contexto Global&lt;/strong&gt; es el encargado de almacenar la información que se va a utilizar en los componentes hijos, y se encarga de proporcionar la información a los componentes hijos. Para crear un &lt;strong&gt;Contexto Global&lt;/strong&gt; se debe utilizar la siguiente estructura:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GlobalContext.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useReducer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GlobalContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GlobalState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="c1"&gt;// Funciones extras&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Acciones
&lt;/h3&gt;

&lt;p&gt;Las &lt;strong&gt;Acciones&lt;/strong&gt; son las funciones que se encargan de manipular la información del &lt;strong&gt;Estado Inicial&lt;/strong&gt;, donde estas funciones se encargan de modificar la información del &lt;strong&gt;Estado Inicial&lt;/strong&gt;. Para crear &lt;strong&gt;Acciones&lt;/strong&gt; se debe utilizar la siguiente estructura:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GlobalActions.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setUsuario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SET_USUARIO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;usuario&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clearUsuario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLEAR_USUARIO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reducer
&lt;/h3&gt;

&lt;p&gt;El &lt;strong&gt;Reducer&lt;/strong&gt; es el encargado de modificar la información del &lt;strong&gt;Estado Inicial&lt;/strong&gt;, donde este se encarga de recibir las &lt;strong&gt;Acciones&lt;/strong&gt; y modificar la información del &lt;strong&gt;Estado Inicial&lt;/strong&gt;. Para crear un &lt;strong&gt;Reducer&lt;/strong&gt; se debe utilizar la siguiente estructura:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GlobalReducer.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GlobalReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SET_USUARIO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLEAR_USUARIO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Provider
&lt;/h3&gt;

&lt;p&gt;El &lt;strong&gt;Provider&lt;/strong&gt; es el encargado de proporcionar la información a los componentes hijos, donde este se encarga de almacenar la información del &lt;strong&gt;Estado Inicial&lt;/strong&gt; y proporcionarla a los componentes hijos. Para crear un &lt;strong&gt;Provider&lt;/strong&gt; se debe utilizar la siguiente estructura:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GlobalProvider.jsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GlobalProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GlobalReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GlobalState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GlobalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GlobalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Colocación del Provider
&lt;/h3&gt;

&lt;p&gt;Para que el &lt;strong&gt;Provider&lt;/strong&gt; pueda ser utilizado en los componentes hijos, se debe colocar en donde es requerido, aunque sea tentador colocarlo en el componente raíz, no es recomendable, ya que puede causar problemas de rendimiento. Para colocar el &lt;strong&gt;Provider&lt;/strong&gt; se debe plantear correctamente el alcance que deseas que tenga este &lt;strong&gt;Provider&lt;/strong&gt;, así que antes de colocarlo, plantea si es necesario que &lt;strong&gt;TODOS&lt;/strong&gt; los componentes van a requerir accesar a la información del &lt;strong&gt;Provider&lt;/strong&gt; o solamente es un módulo aislado que solo requiere lo necesario para sí mismo.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;App.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GlobalProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./GlobalProvider&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GlobalProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Componente&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GlobalProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Consumir el Provider
&lt;/h3&gt;

&lt;p&gt;Para consumir el &lt;strong&gt;Provider&lt;/strong&gt; en los componentes hijos, se debe utilizar el &lt;strong&gt;Hook&lt;/strong&gt; &lt;code&gt;useContext&lt;/code&gt; que proporciona &lt;strong&gt;React&lt;/strong&gt;. Para consumir el &lt;strong&gt;Provider&lt;/strong&gt; se debe utilizar la siguiente estructura:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Componente.jsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GlobalContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./GlobalContext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Componente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GlobalContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usuario&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Funciones personalizadas
&lt;/h3&gt;

&lt;p&gt;A veces es necesario crear funciones personalizadas que no estén relacionadas con el &lt;strong&gt;Estado Inicial&lt;/strong&gt;, para esto se puede agregar funciones extras al &lt;strong&gt;Contexto Global&lt;/strong&gt;. Para agregar funciones extras al &lt;strong&gt;Contexto Global&lt;/strong&gt; se debe utilizar la siguiente estructura:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GlobalContext.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useReducer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GlobalContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GlobalState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="c1"&gt;// Funciones extras&lt;/span&gt;
  &lt;span class="na"&gt;logoutAndRedirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;GlobalProvider.jsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GlobalProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useNavigate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GlobalReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GlobalState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logoutAndRedirect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLEAR_USUARIO&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GlobalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logoutAndRedirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GlobalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recomiendo altamente utilizar las funciones personalizadas cuando se requiere trabajar con el estado del &lt;strong&gt;Provider&lt;/strong&gt; e involucra otros procesos o gestionamiento de muchos cambios en el estado. Esto con el fin de &lt;em&gt;reducir&lt;/em&gt; la cantidad de codigo que puede llegar a involucrarse en el lado de la &lt;strong&gt;Vista&lt;/strong&gt;, y &lt;em&gt;mantener&lt;/em&gt; un orden en la estructura del &lt;strong&gt;Provider&lt;/strong&gt;, promoviendo asi la reutilizacion de codigo y la escalabilidad del mismo.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to setup a service in a SSH Server</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Thu, 18 Jul 2024 19:56:16 +0000</pubDate>
      <link>https://dev.to/sazardev/how-to-setup-a-service-in-a-ssh-server-4iik</link>
      <guid>https://dev.to/sazardev/how-to-setup-a-service-in-a-ssh-server-4iik</guid>
      <description>&lt;p&gt;You get a connection with ssh, and then you run your project or a command. You are innocent and just close the terminal assuming that your command will run forever in the SSH Server. If this was your case (Or you're just curios) let me help you to do a real Service in Linux for your SSH Server.&lt;/p&gt;

&lt;p&gt;First of all we need to go to &lt;code&gt;/etc&lt;/code&gt; in your SSH Server. So, if you are already logged in just put in the terminal:&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="nb"&gt;cd&lt;/span&gt; /etc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/etc&lt;/code&gt; is where we have our system configuration files, it's like our nerve center of our system, so be careful of what you are touching here please. Also, that is why we are putting a service file right here. Let's dive into:&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="nb"&gt;cd &lt;/span&gt;system/system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is where we create a new file called: &lt;code&gt;[name of your service].service&lt;/code&gt;, in my case will be named &lt;code&gt;deploy-frontend.service&lt;/code&gt;. So, in the terminal you will need to add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim deploy-frontend.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we have a new file service! That is great but not all. Let me explain to you the syntax of the new file.&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="o"&gt;[&lt;/span&gt;Unit]
&lt;span class="c"&gt;# Here we describe our service&lt;/span&gt;
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Serve run &lt;span class="k"&gt;for &lt;/span&gt;frontend

&lt;span class="o"&gt;[&lt;/span&gt;Service]
&lt;span class="c"&gt;# Here we are going to detail the actions of our service&lt;/span&gt;
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;path_of_the_command&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /home/dev/app/dist &lt;span class="nt"&gt;-l&lt;/span&gt; 5000
&lt;span class="nv"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always
&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;your_username&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;Install]
&lt;span class="c"&gt;# And here we define what users had this service&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in my case my service looks like this:&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="o"&gt;[&lt;/span&gt;Unit]
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Serve run &lt;span class="k"&gt;for &lt;/span&gt;frontend

&lt;span class="o"&gt;[&lt;/span&gt;Service]
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/serve &lt;span class="nt"&gt;-s&lt;/span&gt; /home/dev/app/dist &lt;span class="nt"&gt;-l&lt;/span&gt; 5000
&lt;span class="nv"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always
&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev

&lt;span class="o"&gt;[&lt;/span&gt;Install]
&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>linux</category>
      <category>ssh</category>
      <category>devops</category>
      <category>cli</category>
    </item>
    <item>
      <title>How to structure your files with VIPER Architecture</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Tue, 16 Jul 2024 23:39:48 +0000</pubDate>
      <link>https://dev.to/sazardev/how-to-structure-your-files-with-viper-architecture-4do</link>
      <guid>https://dev.to/sazardev/how-to-structure-your-files-with-viper-architecture-4do</guid>
      <description>&lt;p&gt;Maybe you already had the theory of how VIPER Architecture work but that's only the THEORY, in the real work can be painful implement a Software Architecture because you can have a lot of cases that you can't know how to implement correctly accordly VIPER Architecture (But this can happen when whatever Architecture). &lt;/p&gt;

&lt;p&gt;I'll explain you how to implement correctly VIPER with a common cases, but if you have an especific scenario you can comment to discuss how VIPER can solvent correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  PhonebookApp (iOS)
&lt;/h2&gt;

&lt;p&gt;A classic one. Let's supouse that you need to do a simple Phonebok application where stores contact.&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="n"&gt;PhonebookApp&lt;/span&gt; &lt;span class="c1"&gt;# Root directory of the application
&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Common&lt;/span&gt; &lt;span class="c1"&gt;# Shared code between features
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Models&lt;/span&gt; &lt;span class="c1"&gt;# Data models representing entities
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Represents a single contact with its information
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Represents a group of contacts
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Utils&lt;/span&gt; &lt;span class="c1"&gt;# Utility classes for common functionalities
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;NetworkManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Handles communication with network services
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;StorageManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Handles data persistence and retrieval
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ViewModels&lt;/span&gt; &lt;span class="c1"&gt;# View models for data presentation
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ContactDetailViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Prepares data for the contact detail view
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ContactGroupListViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Prepares data for the contact group list view
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactListViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Prepares data for the contact list view
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Features&lt;/span&gt; &lt;span class="c1"&gt;# Individual features of the application # Feature for managing a single contact
&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ContactDetail&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Views&lt;/span&gt; &lt;span class="c1"&gt;# UI components for displaying the contact
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactDetailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Xcode Storyboard or SwiftUI view for contact details
&lt;/span&gt;        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Interactors&lt;/span&gt; &lt;span class="c1"&gt;# Business logic for contact data
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactDetailInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Fetches, updates, and deletes contact data
&lt;/span&gt;        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Presenters&lt;/span&gt; &lt;span class="c1"&gt;# Prepares data for the contact detail view
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactDetailPresenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Receives data from interactor and formats it for view
&lt;/span&gt;        &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Routers&lt;/span&gt; &lt;span class="c1"&gt;# Navigation logic for the contact detail screen
&lt;/span&gt;            &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactDetailRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Handles navigation to other features from contact detail # Feature for managing contact groups
&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ContactGroupList&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Views&lt;/span&gt; &lt;span class="c1"&gt;# UI components for displaying contact groups
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactGroupListView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Xcode Storyboard or SwiftUI view for contact group list
&lt;/span&gt;        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Interactors&lt;/span&gt; &lt;span class="c1"&gt;# Business logic for contact group data
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactGroupListInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Fetches, updates, and manages contact groups
&lt;/span&gt;        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Presenters&lt;/span&gt; &lt;span class="c1"&gt;# Prepares data for the contact group list view
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactGroupListPresenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Receives data from interactor and formats it for view
&lt;/span&gt;        &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Routers&lt;/span&gt; &lt;span class="c1"&gt;# Navigation logic for the contact group list screen
&lt;/span&gt;            &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactGroupListRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Handles navigation to other features from contact group list # Feature for managing the list of contacts
&lt;/span&gt;    &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactList&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Views&lt;/span&gt; &lt;span class="c1"&gt;# UI components for displaying contacts
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactListView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Xcode Storyboard or SwiftUI view for contact list
&lt;/span&gt;        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Interactors&lt;/span&gt; &lt;span class="c1"&gt;# Business logic for contact data
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactListInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Fetches, updates, and manages contacts
&lt;/span&gt;        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Presenters&lt;/span&gt; &lt;span class="c1"&gt;# Prepares data for the contact list view
&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactListPresenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Receives data from interactor and formats it for view
&lt;/span&gt;        &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Routers&lt;/span&gt; &lt;span class="c1"&gt;# Navigation logic for the contact list screen
&lt;/span&gt;            &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactListRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Handles navigation to other features from contact list
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt; &lt;span class="c1"&gt;# Entry point and core application logic
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;AppDelegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Manages the application lifecycle
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;SceneDelegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Manages window scene lifecycle and transitions on iOS 13+
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;MainCoordinator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Coordinates navigation between features
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Tests&lt;/span&gt; &lt;span class="c1"&gt;# Unit tests for application components
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;CommonTests&lt;/span&gt; &lt;span class="c1"&gt;# Tests for shared code
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ModelsTests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Unit tests for `Contact` and `ContactGroup` models
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;UtilsTests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Unit tests for `NetworkManager` and `StorageManager`
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;FeaturesTests&lt;/span&gt; &lt;span class="c1"&gt;# Tests for individual features
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ContactDetailTests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Unit tests for contact detail functionality
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ContactGroupListTests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Unit tests for contact group list functionality
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ContactListTests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Unit tests for contact list functionality
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;AppTests&lt;/span&gt; &lt;span class="c1"&gt;# Tests for application entry point
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;AppDelegateTests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swift&lt;/span&gt; &lt;span class="c1"&gt;# Unit tests for `AppDelegate`
&lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Resources&lt;/span&gt; &lt;span class="c1"&gt;# Assets and configuration files
&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xcassets&lt;/span&gt; &lt;span class="c1"&gt;# App icons and other images
&lt;/span&gt;    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;LaunchScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storyboard&lt;/span&gt; &lt;span class="c1"&gt;# Storyboard for the launch screen
&lt;/span&gt;    &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plist&lt;/span&gt; &lt;span class="c1"&gt;# Configuration file for the application
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Shop App (Android)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ShopApp&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gradle&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;AndroidManifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;assets&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;           &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;# app assets like images
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;               &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yourcompany&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shop&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="c1"&gt;# Represents a product with details
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                           &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ProductCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="c1"&gt;# Represents a product category
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ApiManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="c1"&gt;# Handles network communication
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;persistence&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;LocalStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="c1"&gt;# Handles data persistence on device
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ProductRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="c1"&gt;# Provides access to product data
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;features&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;productdetail&lt;/span&gt;  &lt;span class="c1"&gt;# Feature for managing a single product detail
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;contract&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductDetailContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for VIPER communication
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductDetailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for View
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductDetailInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for Interactor
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductDetailPresenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for Presenter
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ProductDetailRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for Router
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ProductDetailRepositoryImpl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Implementation of ProductRepository for product detail
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;presentation&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductDetailPresenterImpl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Implementation of ProductDetailPresenter
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ProductDetailActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Activity for displaying product details
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&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;other&lt;/span&gt; &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;productlist&lt;/span&gt;  &lt;span class="c1"&gt;# Feature for managing the product list
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;contract&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductListContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for VIPER communication
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductListView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for View
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductListInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for Interactor
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductListPresenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for Presenter
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ProductListRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Interface for Router
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ProductListRepositoryImpl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Implementation of ProductRepository for product list
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;presentation&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ProductListPresenterImpl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Implementation of ProductListPresenter
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ProductListActivity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kt&lt;/span&gt; &lt;span class="c1"&gt;# Activity for displaying product list
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;util&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                       &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;# Utility classes
&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;gradle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;gradlew&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bat&lt;/span&gt;  &lt;span class="c1"&gt;# or gradlew (depending on OS)
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gradle&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;gradle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="c1"&gt;# Optional for local development configuration
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>architecture</category>
      <category>mobile</category>
      <category>viper</category>
      <category>development</category>
    </item>
    <item>
      <title>VIPER Architecture</title>
      <dc:creator>Sazardev</dc:creator>
      <pubDate>Mon, 15 Jul 2024 15:59:20 +0000</pubDate>
      <link>https://dev.to/sazardev/viper-architecture-2pb8</link>
      <guid>https://dev.to/sazardev/viper-architecture-2pb8</guid>
      <description>&lt;p&gt;¿You're getting struggle writing your code for Mobile Applications? Let me present you with the &lt;strong&gt;&lt;em&gt;VIPER&lt;/em&gt;&lt;/strong&gt; Architecture, and why this is the &lt;em&gt;BEST&lt;/em&gt; for mobile development.&lt;/p&gt;

&lt;p&gt;V -&amp;gt; View&lt;br&gt;
I -&amp;gt; Interactor&lt;br&gt;
P -&amp;gt; Presenter&lt;br&gt;
E -&amp;gt; Entity&lt;br&gt;
R -&amp;gt; Router&lt;/p&gt;

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

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;view&lt;/em&gt;&lt;/strong&gt; layer handles everything related to what the user sees on his screen. This must be something like the Screen or the componentes in your application.&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%2Fgitnza7yjvwz4ga3vqaz.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%2Fgitnza7yjvwz4ga3vqaz.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Here is where you got the bussines logic of your application. Acts like a mediator between the controller of the screens that see our users and the data from an API, Database. But what is bussines logic? Here is EVERIYTHING related from the usability of our applications, this includes &lt;strong&gt;Data Transformation&lt;/strong&gt;, &lt;strong&gt;Data Handling&lt;/strong&gt;, &lt;strong&gt;Session Handling&lt;/strong&gt;, and a large etc.&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%2F318rsqptzplx0d7u57oq.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%2F318rsqptzplx0d7u57oq.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just keep in mind that in the interactor you will put everything that includes an ACTION from the user, and you need to do the logic to correctly present the expected response to the user.&lt;/p&gt;

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

&lt;p&gt;We already got the bussines logic from the &lt;strong&gt;Interactor&lt;/strong&gt;, so, what's Presenter? The presenter also has bussines logic, but he is the &lt;strong&gt;MEDIATOR&lt;/strong&gt; between the &lt;strong&gt;View&lt;/strong&gt; and &lt;strong&gt;Interactor&lt;/strong&gt;, this was explained in the &lt;strong&gt;Interactor&lt;/strong&gt;, but this layer is the responsibly to communicate with the UI. The classic flow from the &lt;strong&gt;Presenter&lt;/strong&gt; is something like:&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%2F9tcpwaho2zceyy85m1os.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%2F9tcpwaho2zceyy85m1os.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(View) User tap to "Posts" screen&lt;br&gt;
(Presenter) Receive the action and start charging the loading component to the View, also start requesting to the Interactor for the data requested.&lt;br&gt;
(Interactor) Talk to the data source and send it back to the &lt;strong&gt;Presenter&lt;/strong&gt;.&lt;br&gt;
(Presenter) Receive and clean the data and send it to the &lt;strong&gt;View&lt;/strong&gt;&lt;br&gt;
(View) The user is happy to see Karen posts.&lt;/p&gt;

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

&lt;p&gt;Entities are the data models that stand for the application bussines object, can be something like &lt;em&gt;User&lt;/em&gt;, &lt;em&gt;Post&lt;/em&gt;, &lt;em&gt;Comments&lt;/em&gt;. Here is where we represent the object data that will be used for every process in our VIPER Architecture. Also, it is important to keep in mind to not do anything too robust and too flexible, Entity is the core of our app, but like everything, our core needs to be adaptative to every situation.&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%2Fmpn0is69etx15t4rbfj3.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%2Fmpn0is69etx15t4rbfj3.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;For some people this is not the most important, but for the user is &lt;strong&gt;MUST HAVE&lt;/strong&gt; because they want a really powerful system of navigation, they want to have a powerful share and they friend go to the exact path they share, in mobile is a &lt;strong&gt;MUST&lt;/strong&gt; you can't ignore this layer because you need to have to give an excellent experience.&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%2Fvpxc1dimke1ipbh1iddj.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%2Fvpxc1dimke1ipbh1iddj.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But well, too much presentation, but what do the Router Layer? The router manages navigation between screens or modules, also manages the presentation and dismissing views or errors in the view, also this layer protects routes if is required (Like auth session), check the parameters routers. And most important, this is the most decoupled layer but the most responsable for the other layers.&lt;/p&gt;

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

&lt;p&gt;And that is everything about VIPER Architecture, in personal I LOVE this architecture because I am and Flutter/Android developer, if you are a mobile developer consider using this Architecture above the Clean Architecture because is most simple, intuitive, and adaptable for the most Mobile Development cases. &lt;/p&gt;

&lt;p&gt;Hope you enjoy reading and learn something new, please tell me what do you think about this architecture and why you will use it or not use it.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&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%2Fxda7er67xy5n1dt4rhg0.gif" 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%2Fxda7er67xy5n1dt4rhg0.gif" width="280" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>development</category>
      <category>viper</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
