<?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: Maximiliano Burgos</title>
    <description>The latest articles on DEV Community by Maximiliano Burgos (@maxwellnewage).</description>
    <link>https://dev.to/maxwellnewage</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%2F285080%2F0b4414e1-9d08-48b5-8860-44160c1af513.png</url>
      <title>DEV Community: Maximiliano Burgos</title>
      <link>https://dev.to/maxwellnewage</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maxwellnewage"/>
    <language>en</language>
    <item>
      <title>A course on Automating boring staff</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Mon, 03 Jun 2024 16:53:08 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/a-course-on-automating-boring-staff-26g7</link>
      <guid>https://dev.to/maxwellnewage/a-course-on-automating-boring-staff-26g7</guid>
      <description>&lt;p&gt;I was navigating the confines of Udemy when I came across a Python course that powerfully caught my curiosity: &lt;a href="https://www.udemy.com/course/automate/"&gt;Automate the Boring Stuff with Python Programming&lt;/a&gt;. It lasts about nine and a half hours, it's somewhat old, but it captivated me from the first minute.&lt;/p&gt;

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

&lt;p&gt;Above, you can see my certificate, freshly minted and ready to show off on my LinkedIn profile. Many people with too much free time might object with something like, "but the course lasts less than 40 hours, it must be very bad or incomplete." To these types of individuals, I would say that a course is not worth more or less based on the amount of time it takes.&lt;/p&gt;

&lt;p&gt;Sometimes there are 4-hour courses that explain everything in a concise and specific manner, and then there are those famous 60-hour courses where 10 are theory and 50 are excruciating practice. Halfway through the course, you realize that you're repeating most of the concepts. It's like those cartridges with 999 games, where 800 were the same but changed Mario's outfit color (yes, I also went through that golden era).&lt;/p&gt;

&lt;p&gt;The course is basically a video and practice translation of the book of the same name. Although it is several years old (it uses a version of Python from 2015), it remains a gem to admire and is also great for taking the first steps in Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  The content
&lt;/h2&gt;

&lt;p&gt;It should be noted that the entire course is in English, but even if you don't have a strong command of the language, you can understand everything that is happening because Al Sweigart (the course creator) constantly executes commands in the console, demonstrating their results.&lt;/p&gt;

&lt;p&gt;As for the course content itself, we have different sections covering all the fundamentals of Python:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control structures&lt;/li&gt;
&lt;li&gt;Conditional structures&lt;/li&gt;
&lt;li&gt;Functions&lt;/li&gt;
&lt;li&gt;Loops&lt;/li&gt;
&lt;li&gt;Lists and Dictionaries&lt;/li&gt;
&lt;li&gt;String Handling&lt;/li&gt;
&lt;li&gt;File Handling&lt;/li&gt;
&lt;li&gt;Debugging (it hurts a bit because he does it with the Python Shell)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After explaining the basics, the fun begins: Automation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Scraping&lt;/li&gt;
&lt;li&gt;Reading and writing Excel, Word, and PDF files&lt;/li&gt;
&lt;li&gt;Sending and reading emails&lt;/li&gt;
&lt;li&gt;Automating GUI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is worth noting that at the end of the GUI chapter, he shows a script that plays a sushi preparation video game by itself.&lt;/p&gt;

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

&lt;p&gt;The main reason I recommend a course that is already several years old is because of its quality. Al Sweigart explains with love and dedication in every line of code he writes. It is designed for people who want to get into development, but it can surprise even experienced individuals. I got it for free during some sort of sale, if you know about it, don't hesitate to mention it in the comments!&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>El auge y la caída del mercado laboral</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Thu, 30 May 2024 13:19:49 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/el-auge-y-la-caida-del-mercado-laboral-4gh8</link>
      <guid>https://dev.to/maxwellnewage/el-auge-y-la-caida-del-mercado-laboral-4gh8</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5hheqrtbfx439spxnuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5hheqrtbfx439spxnuw.png" alt="Mercado Laboral" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Preparen los ojos, que este artículo, por primera vez desde los ultimos 3 años, no fue creado mediante IA. Bienvenidos a la zona de "no soy un Top Voice y me encanta".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Está claro que el &lt;strong&gt;mercado se volvió más exigente&lt;/strong&gt; en los últimos años. Tuvimos una pandemia que cambió las normas del trabajo presencial (por suerte) y generó puestos de trabajo por todos los horizontes, hasta donde no llega el sol.&lt;/p&gt;

&lt;p&gt;Durante un &lt;strong&gt;período de gracia&lt;/strong&gt;, los juniors/trainees tenían una entrada fácil; mientras que los seniors éramos dioses del Olimpo. Había &lt;strong&gt;fondos&lt;/strong&gt; para todo el mundo: las startups chicas se potenciaron, y las empresas grandes explotaron.&lt;/p&gt;

&lt;p&gt;Pero &lt;strong&gt;la pandemia terminó&lt;/strong&gt; hace tiempo, y como toda buen época dorada, le sigue una devastadora: miles de despidos, acciones en bajada, bootcamps que prometieron oro y gente que llegó tarde al baile.&lt;/p&gt;

&lt;p&gt;Al mismo tiempo, &lt;strong&gt;los requisitos técnicos empezaron a complejizarse&lt;/strong&gt;: las empresas necesitan un desarrollador que pueda cubrir el rol de dos o tres personas para abaratar ese presupuesto que se detonó por la fluctuación pandémica.&lt;/p&gt;

&lt;p&gt;Mucha gente esta plantéandose &lt;strong&gt;cambiar de profesión&lt;/strong&gt;, otros quieren tomarse un período de tres a seis meses para esperar que el mercado se vuelva a estabilizar.&lt;/p&gt;

&lt;p&gt;Como parte de este mar furioso, voy a intentar dar un poco de luz al asunto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planes de Acción
&lt;/h2&gt;

&lt;p&gt;En primer instancia, &lt;strong&gt;no hay que desesperarse&lt;/strong&gt;. Todos, repito, absolutamente todos estamos pasando por esta crisis. Si, incluso la gente con empleo perdió la opción de moverse porque el mercado esta parado para &lt;strong&gt;todos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por supuesto esto son generalidades, porque empleo hay siempre y búsquedas también. Pero esta claro que el gráfico tiende a la baja en los últimos períodos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trabaja en tu CV
&lt;/h2&gt;

&lt;p&gt;Por otro lado, es un excelente momento para &lt;strong&gt;mejorar el CV&lt;/strong&gt;. Y no hablo de tocar un par de detalles en la experiencia, sino trabajar realmente en un refactor del mismo. Pueden tomar el mío de referencia, lo copian y le cambian lo que necesiten.&lt;/p&gt;

&lt;p&gt;Un consejo de oro que me dió un buen recruiter una vez es el siguiente: &lt;strong&gt;crea un CV distinto por cada rol al que postules&lt;/strong&gt;. Esto no significa mentir en la experiencia, sino remarcar los puntos relevantes al entrevistador que te está contratando.&lt;/p&gt;

&lt;p&gt;Casi &lt;strong&gt;nadie suele tomar este consejo&lt;/strong&gt;, porque implica tiempo y dedicación hacia un documento que no implica la obtención del empleo de forma directa. Pero ten en cuenta que &lt;strong&gt;buscar trabajo, es un trabajo&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caso de Uso
&lt;/h2&gt;

&lt;p&gt;Piensa, por ejemplo, en una empresa estilo EdTech: se abre una búsqueda de un nuevo profesor y contenidista.&lt;/p&gt;

&lt;p&gt;En tu caso, sos un desarrollador con muchos años de experiencia en Python. Eso está muy bien. Pero tus experiencias dicen cosas como:&lt;/p&gt;

&lt;p&gt;Trabajé en el desarrollo de una app en Django que permite hacer compras online. Conjunto con mi equipo, integramos grandes funcionalidades que llevaron al producto a un nuevo nivel.&lt;/p&gt;

&lt;p&gt;A ver, no está mal. Pero tampoco es relevante a la búsqueda que aplicaste. Quizá te sirve para una empresa de E-commerce, donde ven este tipo de detalles. Vamos a adaptarla para la búsqueda actual:&lt;/p&gt;

&lt;p&gt;He contribuido en la implementación de una app en Django que permite hacer compras online, participando en el desarrollo; así como también en la documentación interna y externa, generando una mayor comprensión del producto a la hora de utilizarlo y seguir expandiendo sus funcionalidades.&lt;/p&gt;

&lt;p&gt;Habrás notado que la diferencia radica en las palabras clave: contribuir, documentación, comprensión. Son detalles que busca una EdTech; que sepas comunicar tus ideas y crear contenidos claros, y sobretodo, útiles para quien los consuma.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calma, que todo llega
&lt;/h2&gt;

&lt;p&gt;En la primer semana que me desvincularon, estaba desesperado: el mismo día, una hora después, activé todas las búsquedas, actualicé mi CV y me armé un plan de estudios entre otras cosas que fui haciendo.&lt;/p&gt;

&lt;p&gt;No me tomé un período de descanso, lo que me llevó a enfermarme a la semana siguiente. Esa misma semana, las propuestas seguían sin aparecer, y me empezaban a rechazar las solicitudes sencillas de Jobs en LinkedIn. No llegaban ni a conocerme.&lt;/p&gt;

&lt;p&gt;Mi salud se iba deteriorando, y el estrés subía por las nubes. También odiaba leer a los "Top Voices" con sus ideas simplonas y posts generados por IA. Me enojaba ver cómo aprovechaban la ola de despidos para crear sus reflexiones sin profundidad. Nunca deja de sorprenderme el poder de usar párrafos enteros decorados de frases que no transmiten nada.&lt;/p&gt;

&lt;p&gt;De hecho, me enojaba más leyendo los comentarios del estilo "excelente reflexión, estoy muy de acuerdo". Así que decidí tomar un poco de distancia de LinkedIn, y centrarme en lo que más amo: desarrollar.&lt;/p&gt;

&lt;p&gt;La tercer semana me llovieron las propuestas. Y no fue ninguna de las que envié 🤣. Todas llegaron de recruiters que me encontraron. Hoy no me dan las manos para todos los procesos interesantes que estoy pasando.&lt;/p&gt;

&lt;p&gt;Por lo tanto, si estás pasando una situación de "sequía laboral", tranquilo, es una cuestión de tiempo. Pero en el transcurso de ello, no te quedes sentado esperando: trabaja en tu "imagen personal". Oh no! Me he convertido en un top voice sin darme cuenta! 😢.&lt;/p&gt;

&lt;p&gt;Pero en serio: tu perfil de LinkedIn, el CV, las rutas de aprendizaje que armes, la gente que vayas conociendo en el camino y todo lo demás, es importantísimo. Quizá encuentres trabajo en un mes o más tiempo; pero todo el proceso de crecimiento que tengas en el medio es la parte más importante de esto.&lt;/p&gt;

&lt;p&gt;Las crisis nos destruyen, o nos fortalecen. Si, definitivamente me he convertido en un top voice.&lt;/p&gt;

&lt;p&gt;Nos vemos en el siguiente artículo!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>career</category>
    </item>
    <item>
      <title>Un nuevo podcast ha nacido: En Código</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Wed, 08 Nov 2023 13:08:50 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/un-nuevo-podcast-ha-nacido-en-codigo-3goi</link>
      <guid>https://dev.to/maxwellnewage/un-nuevo-podcast-ha-nacido-en-codigo-3goi</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uG8jaCDf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pawonf79zwsv90c6hhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uG8jaCDf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pawonf79zwsv90c6hhc.png" alt="En Código Podcast" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Bienvenidos y bienvenidas a un nuevo episodio", es el inicio de un &lt;a href="https://podcasters.spotify.com/pod/show/maxi-burgos9"&gt;podcast&lt;/a&gt; que está conquistando el oído de cada oyente alrededor del mundo.&lt;/p&gt;

&lt;p&gt;"En Código Podcast" es mi espacio personal para hablar de mis experiencias en mis 14 años trabajando en la industria. Un recorrido que incluso va más allá, llegando hasta mis primeros años del colegio secundario, momento en el cual se me ocurrió empezar un sueño que más tarde se transformaría en una vocación: desarrollar software.&lt;/p&gt;

&lt;p&gt;Los números hablan solos: en cuestión de una semana, mi &lt;a href="https://podcasters.spotify.com/pod/show/maxi-burgos9"&gt;podcast&lt;/a&gt; ya alcanzó casi 200 reproducciones:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zHuRQ18I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3pim48zfz54ijchf3vir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zHuRQ18I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3pim48zfz54ijchf3vir.png" alt="Spotify Estadísticas" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Todo esto explotó gracias a la comunidad &lt;a href="https://www.reddit.com/r/devsarg/"&gt;r/devsarg&lt;/a&gt; en Reddit, por un &lt;a href="https://www.reddit.com/r/devsarg/comments/17p2ec0/acabo_de_lanzar_un_podcast_de_sistemas_y/"&gt;post&lt;/a&gt; donde comenté la existencia de este podcast y mi proyecto con él.&lt;/p&gt;

&lt;p&gt;Tuvo una aceptación inmensa, de tal forma que en el último episodio me tomé un tiempo para leer los comentarios más destacados y responder preguntas en vivo.&lt;/p&gt;

&lt;h1&gt;
  
  
  El futuro del podcast
&lt;/h1&gt;

&lt;p&gt;Mi idea es traer invitados, mejorar el sonido en cada episodio, traer ideas nuevas y abrir debates sobre la industria y el desarrollo de software.&lt;/p&gt;

&lt;p&gt;En este momento, "En Código" es un proyecto en pañales, y está empezando a dar sus primeros pasos. Se puede transformar y evolucionar en todo tipo de aspectos, pero lo más emocionante, es que ustedes van a estar ahí, acompañándome en esta gran aventura.&lt;/p&gt;

&lt;p&gt;Pueden escuchar "En Código Podcast" en:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://podcasters.spotify.com/pod/show/maxi-burgos9"&gt;Spotify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLp7PPjAxisAKVKre0a5tnjoFetQkvkZ9i"&gt;Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/us/podcast/en-c%C3%B3digo-podcast/id1715009724"&gt;Apple Podcast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://music.amazon.com/podcasts/f7bfd4fc-8216-488a-a736-a1f67805416d"&gt;Amazon Music&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En Spotify es donde más estoy atento, por lo cual les recomiendo que si quieren dejar algún comentario, sea en esta plataforma.&lt;/p&gt;

&lt;p&gt;También estoy publicando los nuevos episodios en &lt;a href="https://twitter.com/maxwellnewage"&gt;Twitter&lt;/a&gt; (o X...).&lt;/p&gt;

&lt;p&gt;Disfruten del podcast y ¡Hasta la próxima!&lt;/p&gt;

</description>
      <category>podcast</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Diario de Python | #18. Un curso de Automatizar cosas aburridas</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Thu, 06 Jul 2023 20:06:56 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/diario-de-python-18-un-curso-de-automatizar-cosas-aburridas-2777</link>
      <guid>https://dev.to/maxwellnewage/diario-de-python-18-un-curso-de-automatizar-cosas-aburridas-2777</guid>
      <description>&lt;p&gt;Bueno, quizá no sea la persona más comprometida en esto de publicar a diario o semanalmente. Sepan disculpar nuevamente, pero básicamente estoy haciendo unas tres o cuatro cosas en simultáneo que involucran trabajar y generar contenido para ustedes.&lt;/p&gt;

&lt;p&gt;Parte de la culpa, confieso, es del &lt;a href="https://www.linkedin.com/newsletters/diario-de-python-7078405957302595584/"&gt;nuevo newsletter&lt;/a&gt; que estoy publicando en LinkedIn, el cual los invito a suscribirse. Mi objetivo es traerles nuevos contenidos sobre cosas que voy investigando y aplicando en mi día a día pythonista. Es más acotado que este diario, pero a su vez tiene muchos links, de esos que a ustedes les gusta clickear.&lt;/p&gt;

&lt;p&gt;No obstante, insisto en mi plan de no abandonarlos (porque son geniales, cada uno de ustedes, queridos lectores) y trabajar en el contenido de este diario en todos los huecos de tiempo que encuentre.&lt;/p&gt;

&lt;p&gt;Sin más preámbulos, vamos a sumergirnos en las historias de mi nuevo viaje. Tomen asiento y disfruten las vistas, porque el destino queda un poco lejos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Un curso interesante
&lt;/h2&gt;

&lt;p&gt;Estaba navengando por los confines de Udemy cuando me crucé con un curso de Python, el cual atrajo poderosamente mi curiosidad: &lt;a href="https://www.udemy.com/course/automate/"&gt;Automate the Boring Stuff with Python Programming&lt;/a&gt;, o en español "Automatizá cosas aburridas en Python". Dura unas nueve horas y media, es algo viejo, pero me conquistó desde el minuto cero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vFAxLIoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6d4jab6q715eow49enki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vFAxLIoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6d4jab6q715eow49enki.png" alt="Certificado Curso" width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Arriba pueden ver mi certificado, recién salido del horno y listo para presumir en mi perfil de LinkedIn. Mucha gente con exceso de tiempo libre puede objetar algo como: "pero el curso dura menos de 40 horas, debe ser muy malo o incompleto". Para este tipo de seres, les comento que un curso no vale más o menos por la cantidad de tiempo que implique. A veces hay cursos de 4 horas que explican todo de forma condensada y específica; y otras tenemos esos famosos cursos de 60 horas donde 10 son de teoría y 50 de prácticas insufribles. En la mitad del curso te terminas dando cuenta que estás repitiendo la mayoría de los conceptos. Es como esos cartuchos de 999 juegos, donde 800 eran iguales pero cambiaban el color del atuendo de Mario (si, yo también pasé por esa época dorada).&lt;/p&gt;

&lt;p&gt;El curso es básicamente una traducción a modo de video y prácticas de su libro con el mismo nombre. Si bien tiene sus años (usa una versión de Python del 2015), no deja de ser una joya para admirar; y también dar los primeros pasos en Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  El contenido
&lt;/h2&gt;

&lt;p&gt;Cabe aclarar que todo el curso esta en inglés, pero incluso aunque no tengan un dominio del lenguaje, pueden comprender todo lo que está ocurriendo porque Al Sweigart (creador del curso) ejecuta constantemente comandos en consola, demostrando sus resultados.&lt;/p&gt;

&lt;p&gt;En cuanto al contenido del curso en sí, tenemos distintas secciones que abarcan todos los fundamentos de Python:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Estructuras de control&lt;/li&gt;
&lt;li&gt;Estructuras condicionales&lt;/li&gt;
&lt;li&gt;Funciones&lt;/li&gt;
&lt;li&gt;Bucles&lt;/li&gt;
&lt;li&gt;Listas y Diccionarios&lt;/li&gt;
&lt;li&gt;Manejo de Strings&lt;/li&gt;
&lt;li&gt;Manejo de Archivos&lt;/li&gt;
&lt;li&gt;Debugging (duele un poco porque lo hace con la Python Shell)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Luego de explicarte las bases, empieza lo bueno: Automatizar cosas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Scrapping&lt;/li&gt;
&lt;li&gt;Leer y escribir archivos de Excel, Word y PDF&lt;/li&gt;
&lt;li&gt;Enviar y leer mails&lt;/li&gt;
&lt;li&gt;Automatizar GUI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cabe destacar que al final del capítulo de GUI, muestra un script que juega solo a un videojuego de preparar sushi.&lt;/p&gt;

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

&lt;p&gt;La razón principal por la cual recomiendo un curso que ya tiene sus años, es por la calidad del mismo. Al Sweigart explica con amor y dedicación en cada línea de código que escribe. Esta pensado para gente que quiera introducirse en desarrollo, pero puede sorprender a más de un experimentado en la materia. Yo lo conseguí gratis en alguna especie de rebaja, si la conocen, ¡no duden en escribirla en los comentarios!&lt;/p&gt;

&lt;p&gt;Por cierto, estoy preparando unos materiales muy interesantes para el próximo capítulo del diario, ¡estén atent@s y nos vemos en el siguiente!&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>spanish</category>
      <category>python</category>
    </item>
    <item>
      <title>El desafío de la educación en sistemas</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Mon, 26 Jun 2023 16:39:24 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/el-desafio-de-la-educacion-en-sistemas-55pm</link>
      <guid>https://dev.to/maxwellnewage/el-desafio-de-la-educacion-en-sistemas-55pm</guid>
      <description>&lt;p&gt;Hace un tiempo que no creaba uno de esos artículos de &lt;strong&gt;opinión&lt;/strong&gt; que tanto me pide la comunidad. Vengo trabajando en artículos &lt;strong&gt;técnicos&lt;/strong&gt;, los cuales no suelen tener una llegada tan amplia como los anteriores; dado que somos &lt;strong&gt;animales sociales&lt;/strong&gt;: podemos estar discutiendo semanas sobre la modalidad de trabajo remoto, pero cuando hay que estudiar el comportamiento de una función, no hay debate.&lt;/p&gt;

&lt;p&gt;Como Jasnah Kholin en &lt;a href="https://es.wikipedia.org/wiki/El_archivo_de_las_tormentas"&gt;El Archivo de las Tormentas&lt;/a&gt;, sueño con &lt;strong&gt;reunir mentes brillantes&lt;/strong&gt; y establecer debates que sean fructíferos para potenciar el progreso y nos permitan trazar los próximos pasos de un &lt;strong&gt;futuro&lt;/strong&gt; que puede ser &lt;strong&gt;espectacular o lamentable&lt;/strong&gt; en partes iguales.&lt;/p&gt;

&lt;p&gt;Este tipo de debate es el que traigo a &lt;strong&gt;mis clases&lt;/strong&gt;, y a veces, por al menos un par de días, logro generarlo. Sentarse sobre un algoritmo y &lt;strong&gt;entender por qué las cosas funcionan&lt;/strong&gt; de determinada manera, &lt;strong&gt;es solo la meta&lt;/strong&gt;. El &lt;strong&gt;verdadero&lt;/strong&gt; gozo está en el &lt;strong&gt;problema&lt;/strong&gt;: los métodos, las suposiciones, la conjetura o cualquier herramienta que nos permita avanzar hacia una &lt;strong&gt;solución&lt;/strong&gt;. En este camino del &lt;strong&gt;proceso cognitivo&lt;/strong&gt; es donde se puede potencial el verdadero aprendizaje.&lt;/p&gt;

&lt;p&gt;Por eso habrán notado que muchos &lt;strong&gt;profesores&lt;/strong&gt; no entregan una solución, sino que esperan a que el alumno logre indagar en la misma. Preparan el camino y &lt;strong&gt;dejan que sus estudiantes lleguen a la conclusión por ellos mismos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Y esto, mis queridos lectores, es &lt;strong&gt;el desafío de la educación&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Procesos educativos
&lt;/h2&gt;

&lt;p&gt;Los profesores nos dividimos en dos categorías básicas que me acabo de inventar por el beneficio de la trama:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Académicos&lt;/strong&gt;: son los que estudian una carrera docente y se dedican puramente a enseñar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Informales&lt;/strong&gt;: son los que se especializaron en un area por años, y tienen experiencia tanto en el campo de la aplicación como en la educación; pero no estudiaron una carrera docente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yo entraría en el tipo &lt;strong&gt;informal&lt;/strong&gt;, aunque digamos que sí hice un par de cursos para elaborar &lt;strong&gt;estrategias académicas&lt;/strong&gt; y entender cómo transmitir el conocimiento hacia un estudiante.&lt;/p&gt;

&lt;p&gt;Mucha gente cree que puede enseñar sólo porque sabe de un tema, y esto es un grave error: así como &lt;strong&gt;cada persona es única&lt;/strong&gt; y se distingue por sus propios aspectos de su personalidad, también lo es su método para &lt;strong&gt;asimilar conocimientos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;La palabra "asimilar" es extremadamente importante: &lt;strong&gt;no somos máquinas que absorben información&lt;/strong&gt;. Nuestra memoria tiene un límite, y el cerebro trabaja mediante "atajos" para evitar un consumo elevado de energía. Si, efectivamente &lt;strong&gt;nuestra mente optimiza la información&lt;/strong&gt;, la "indexa" todo el tiempo.&lt;/p&gt;

&lt;p&gt;Por esta razón, cuando hablamos de &lt;strong&gt;asimilación&lt;/strong&gt;, nos referimos a la acción de &lt;strong&gt;transformar&lt;/strong&gt; determinada &lt;strong&gt;información&lt;/strong&gt; del exterior y &lt;strong&gt;procesarla&lt;/strong&gt; con nuestros conocimientos actuales. Así funcionamos desde que tenemos uso de razón: &lt;strong&gt;la mente relaciona conceptos y crea mapas de comprensión&lt;/strong&gt;. Entonces cuando recurrimos a la &lt;strong&gt;memoria&lt;/strong&gt;, podemos hacer uso de &lt;strong&gt;palabras claves&lt;/strong&gt; que nos lleven a recuerdos almacenados más complejos. Como ven, todo lo que inventamos en materia de informática no es más que una simulación de nuestros &lt;strong&gt;procesos cognitivos&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  El problema
&lt;/h2&gt;

&lt;p&gt;Con todo lo que expuse anteriormente, puedo definir que, para mi, enseñar es &lt;strong&gt;garantizar las herramientas&lt;/strong&gt; necesarias para que el &lt;strong&gt;proceso de asimilación&lt;/strong&gt; de conocimentos se genere de forma &lt;strong&gt;eficiente y correcta&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El problema radica en que &lt;strong&gt;cada persona aprende de maneras distintas&lt;/strong&gt; y viene con conocimientos anteriores que son (a veces, o casi siempre) muy distintos entre alumnos.&lt;/p&gt;

&lt;p&gt;No es lo mismo &lt;strong&gt;enseñar a programar&lt;/strong&gt; a un estudiante de &lt;strong&gt;universidad&lt;/strong&gt; que uno de &lt;strong&gt;secundaria&lt;/strong&gt;. Además, &lt;strong&gt;la edad influye&lt;/strong&gt; de forma significativa: a los 20 años tenés una energía y un potencial de aprendizaje mucho más amplio que a los 30. Mucha gente insiste en que estudiar de joven es lo más conveniente, y tienen razón: asimilamos mucho más conocimiento porque &lt;a href="https://www.lanacion.com.ar/sociedad/nuevo-estudio-como-envejece-el-cerebro-a-lo-largo-de-los-anos-nid02032023/"&gt;nuestra sinapsis es más eficiente&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Siempre se trata de lo mismo: aprender lo suficiente en una edad temprana y así optimizar los procesos cognitivos en el futuro. Sobre esto, quiero aclarar un punto crítico al respecto: mientras lees este artículo y tenes, supongamos, 30 o 40 años, debes estar conteniendo cierto enojo o desesperanza. Dejame explicarte que empezar a aprender algo de cero en tu edad, es perfectamente posible. La diferencia quizá radique en que simplemente te cueste un poco más que a personas más jóvenes. Pero aún así, incluso aunque no exista una relación directa, muchos conocimientos que ya tenés van a ser aplicables a tus nuevos estudios, sea sistemas u otra rama.&lt;/p&gt;

&lt;p&gt;Volviendo al problema inicial, mi experiencia como profesor me permite saber si una clase me esta siguiendo en el contenido que estoy exponiendo. Soy consciente de que tengo un &lt;strong&gt;tiempo establecido&lt;/strong&gt; donde voy a &lt;strong&gt;explicar algo&lt;/strong&gt;; y que cada alumno va a tener &lt;strong&gt;otro tiempo&lt;/strong&gt; completamente &lt;strong&gt;distinto&lt;/strong&gt; en el que va a &lt;strong&gt;entender dicho concepto&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Entonces, haga lo que haga, me encuentro con una clase que aprende con cierta &lt;strong&gt;disparidad&lt;/strong&gt;: algunos saben mucho, otros pocos. En la búsqueda de una solución, he creado &lt;strong&gt;estrategias&lt;/strong&gt; que hoy día sigo poniendo en práctica para &lt;strong&gt;equilibrar la balanza&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ejercitación y liderazgo
&lt;/h2&gt;

&lt;p&gt;Al ser un profesor de tipo &lt;strong&gt;informal&lt;/strong&gt;, conozco el terreno &lt;strong&gt;laboral&lt;/strong&gt;. Esto afecta a mis clases de forma &lt;strong&gt;positiva&lt;/strong&gt;: yo no veo un &lt;strong&gt;aula&lt;/strong&gt;, sino una &lt;strong&gt;oficina&lt;/strong&gt;, un equipo de trabajo. Con esta idea en mente, cada &lt;strong&gt;ejercicio&lt;/strong&gt; en realidad es una tarea de &lt;strong&gt;proyecto&lt;/strong&gt;; por lo cual los alumnos ven un &lt;strong&gt;objetivo claro y tangible&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Esto implica que a la hora de proponer un ejercicio, &lt;strong&gt;no se aplica el típico modelo individualista de resolución "secreta"&lt;/strong&gt; y que genera copias y plagios entre alumnos. En mi formación, yo fomento el &lt;strong&gt;trabajo en equipo&lt;/strong&gt;. Si un alumno va más lento que otro, se potencia al trabajar con alguien que tiene mayor velocidad. Se crea lo que llamo una &lt;strong&gt;retroalimentación de conocimientos&lt;/strong&gt;. Entre ellos aprenden mucho más que rompiéndose la cabeza solos.&lt;/p&gt;

&lt;p&gt;Además de &lt;strong&gt;mejorar la balanza del conocimiento general&lt;/strong&gt;, también empiezan a crearse &lt;strong&gt;líderes&lt;/strong&gt; que pueden sacar el máximo potencial de cada alumno, porque trabajan sobre la idea de sacar un requerimiento adelante &lt;strong&gt;sin recurrir al individualismo&lt;/strong&gt; de ser "el mejor alumno".&lt;/p&gt;

&lt;h2&gt;
  
  
  Remover la idea de reprobación
&lt;/h2&gt;

&lt;p&gt;En mis clases &lt;strong&gt;no existe la "reprobación"&lt;/strong&gt; como tal. Por supuesto, &lt;strong&gt;evalúo&lt;/strong&gt; cada alumno y tiendo a ser más exigente que otros profesores en general; pero transmito la idea de "llegar al aprobado". Esto significa, &lt;strong&gt;pedirles cambios hasta que las cosas estén bien hechas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Siento que &lt;strong&gt;reprobar es rechazar&lt;/strong&gt;: cuando estudiaba en la universidad y no aprobaba un parcial, esto representaba una &lt;strong&gt;derrota&lt;/strong&gt;. Me &lt;strong&gt;separaba&lt;/strong&gt; de otros compañeros que si aprobaban y me resultaba &lt;strong&gt;frustrante&lt;/strong&gt;. En mi rol como formador, quiero &lt;strong&gt;evitar&lt;/strong&gt; este tipo de &lt;strong&gt;efectos negativos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A fin de cuentas, &lt;strong&gt;en un trabajo no te "reprueban"&lt;/strong&gt; un requerimiento, &lt;strong&gt;sino que te "piden cambios"&lt;/strong&gt; para llegar al objetivo planteado. Este es exactamente el funcionamiento de GitHub y sus Pull Requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Romper la brecha profesor - estudiante
&lt;/h2&gt;

&lt;p&gt;Este probablemente sea un &lt;strong&gt;punto de inflexión&lt;/strong&gt; en muchos de mis colegas: un profesor que pretende la &lt;strong&gt;igualdad&lt;/strong&gt;, perdería el &lt;strong&gt;respeto&lt;/strong&gt; por falta de &lt;strong&gt;jerarquía&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En mi caso personal, nunca me llevé bien con el asunto de las jerarquías: ya aprendimos leyendo &lt;a href="https://es.wikipedia.org/wiki/1984_(novela)"&gt;1984&lt;/a&gt; &lt;strong&gt;que la obediencia deja secuelas y afecta las libertades personales&lt;/strong&gt;. El progreso se ve pausado y se enseña a través del &lt;strong&gt;miedo&lt;/strong&gt;. Esto es eficiente para crear sociedades alienadas; y si consideramos que yo adoro el &lt;strong&gt;pensamiento crítico&lt;/strong&gt;, esto es completamente &lt;strong&gt;incompatible&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;La cuestión es que podemos evitar la jerarquía y aún así tener ese respeto. Por supuesto, siempre hay gente que se quiere aprovechar de esto y romper el clima, pero se puede charlar de forma individual (o incluso grupal) para subsanar este comportamiento, que probablemente venga de un problema más profundo que la clase en sí misma.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Si rompemos la brecha, desaparece el nerviosismo&lt;/strong&gt;: un alumno no tiene miedo a preguntarle a su par acerca de un problema que encontró. Lo mismo se puede aplicar al profesor si lo ve como una persona accesible, y no una figura de &lt;strong&gt;autoridad inalcanzable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;De hecho, si aplicamos bien la regla, podemos obtener &lt;strong&gt;admiración&lt;/strong&gt;. La clave está en mantener el sentido de la &lt;strong&gt;autoridad implícita&lt;/strong&gt;: los estudiantes saben que tienen que seguir tus consejos y cumplir con las entregas en clase. Si tenés que &lt;strong&gt;aclararlo&lt;/strong&gt;, es posible que empieces a &lt;strong&gt;abrir esa brecha&lt;/strong&gt; y separarte de la estrategia inicial que te acabo de plantear.&lt;/p&gt;

&lt;h2&gt;
  
  
  El ego es peligroso
&lt;/h2&gt;

&lt;p&gt;Las personas más &lt;strong&gt;atrayentes&lt;/strong&gt; en la sociedad son aquellas que no se andan regodiando de sus logros, o hablan de si mismas todo el tiempo. Irónicamente, la mayoría de la gente alza su ego al cielo y demuestra que su opinión es increíble y nadie lo pensó antes.&lt;/p&gt;

&lt;p&gt;Es cuestión de entrar a LinkedIn y encontrarse recomendaciones de "gurús" que te van a explicar &lt;strong&gt;cómo vivir tu vida&lt;/strong&gt;; gente convencida de que el trabajo en X tecnología &lt;strong&gt;es lo único que genera dinero&lt;/strong&gt;; personas que emiten una opinión y cuando querés armar debate porque expresas oposición, &lt;strong&gt;te responden con "no comparto, pero es tu opinión"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me exaspera&lt;/strong&gt; este intento de &lt;strong&gt;alzar imperio&lt;/strong&gt;s basados en visiones &lt;strong&gt;subjetivas&lt;/strong&gt;. Es un mar de &lt;strong&gt;dogmatismo&lt;/strong&gt; que no ayuda a nadie; y &lt;strong&gt;confunde&lt;/strong&gt; a mucha gente que luego lleva esas ideas como una nueva &lt;strong&gt;religión&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El pensamiento crítico&lt;/strong&gt; que fomento se basa en cuestionar las ideas y formar las propias. Pero si vos expresas una opinión y yo te doy un contra argumento, &lt;strong&gt;espero un debate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por supuesto, también &lt;strong&gt;afecta al sector docente&lt;/strong&gt;. Muchos profesores creen que los métodos por los cuales ellos aprendieron son los &lt;strong&gt;mejores&lt;/strong&gt;; y esto es muy &lt;strong&gt;lógico&lt;/strong&gt;: les resultaron &lt;strong&gt;eficientes&lt;/strong&gt; y lo quieren aplicar al resto. Pero a su vez, es &lt;strong&gt;erróneo&lt;/strong&gt;: enseñar es como aplicar el &lt;strong&gt;método científico&lt;/strong&gt;. Es partir de una &lt;strong&gt;hipótesis&lt;/strong&gt; y experimentar hasta llegar a convertirlo en una &lt;strong&gt;teoría&lt;/strong&gt; que quizá sea derribada en el futuro.&lt;/p&gt;

&lt;p&gt;Debemos &lt;strong&gt;reconciliarnos&lt;/strong&gt; con la idea de que todo esta sujeto al &lt;strong&gt;cambio&lt;/strong&gt;. No casarse con un método de enseñanza, sino ponerlo todo a prueba. &lt;strong&gt;Rechacemos el dogmatismo y abracemos el pensamiento crítico&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  La gente no lee
&lt;/h2&gt;

&lt;p&gt;Si llegaste a esta parte de mi artículo leyendo todo, &lt;strong&gt;te felicito&lt;/strong&gt;, pertenecés al 5% de la población mundial que lee. El &lt;strong&gt;foco de atención&lt;/strong&gt; cada año es más &lt;strong&gt;reducido&lt;/strong&gt;; y sin una obligación, la gente no lee casi nada en general.&lt;/p&gt;

&lt;p&gt;Entiendo que puedo parecer un exagerado en este momento, pero &lt;strong&gt;intenta hacer la prueba&lt;/strong&gt;: compartí este artículo en tus redes y fijate cuántos opinólogos van a darte &lt;strong&gt;sermones por el título&lt;/strong&gt; sin entrar al artículo. Te invito a comentarme el experimento.&lt;/p&gt;

&lt;p&gt;En una &lt;strong&gt;clase&lt;/strong&gt; pasa algo &lt;strong&gt;similar&lt;/strong&gt;: si generas un manual que sea opcional, el famoso "contenido complementario", menos de la mitad lo va a leer voluntariamente. Muchos probablemente no lo abran. Esto se debe a que &lt;strong&gt;nos atrae más lo visual que lo textual&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por eso las &lt;strong&gt;publicidades funcionan&lt;/strong&gt;: te invaden con &lt;strong&gt;colores&lt;/strong&gt; vivos y atenuantes, acompañados de una &lt;strong&gt;frase muy corta&lt;/strong&gt;, al estilo "me encanta" de McDonalds. En NetFlix entras al contenido de una película o serie porque reproduce el trailer previamente, pero seguramente no leas la descripción del costado.&lt;/p&gt;

&lt;p&gt;Nos encantan los &lt;strong&gt;estímulos visuales&lt;/strong&gt;, fuimos programados así por defecto. Entonces como profesores deberíamos poder jugar con esto, &lt;strong&gt;no luchar una guerra que no podemos ganar&lt;/strong&gt;. Una forma que personalmente me gusta y estuve viendo en LinkedIn, es armar una &lt;strong&gt;serie de slides&lt;/strong&gt; (diapositivas) estilo "apuntes de clase" con muchos colores y con una tipografía que simula la escritura manual.&lt;/p&gt;

&lt;p&gt;Este tipo de contenidos alienta a &lt;strong&gt;leer&lt;/strong&gt;, mirar &lt;strong&gt;gráficas&lt;/strong&gt;, y &lt;strong&gt;aprender&lt;/strong&gt; en el proceso. &lt;a href="https://teloexplicocongatitos.com/"&gt;Te lo explico con gatitos&lt;/a&gt; es el claro ejemplo de estímulo visual atrayente. Se explican conceptos con un texto corto y gatos preciosos en pantalla. Cumple su función: enseña y &lt;strong&gt;entretiene&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;El desafío de la educación nos invita a &lt;strong&gt;mantenernos despiertos&lt;/strong&gt; como profesores: debemos &lt;strong&gt;buscar soluciones&lt;/strong&gt; constantes al trabajo de introducir conocimientos nuevos en distintos estudiantes. Trabajar en el proceso de &lt;strong&gt;asimilación&lt;/strong&gt; y &lt;strong&gt;automatizar tareas&lt;/strong&gt; (como la retroalimentación) es parte de nuestro trabajo diario.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>learning</category>
    </item>
    <item>
      <title>Diario de Python | #17. un paseo por Flake8</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Wed, 21 Jun 2023 16:36:30 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/diario-de-python-17-un-paseo-por-flake8-33do</link>
      <guid>https://dev.to/maxwellnewage/diario-de-python-17-un-paseo-por-flake8-33do</guid>
      <description>&lt;p&gt;Antes de preparar una clase, investigo a fondo los temas, incluso aunque ya los conozca. Siempre se pueden encontrar nuevas formas de hacer y pensar las cosas. Por eso cuando empecé con Python y me crucé con la &lt;a href="https://peps.python.org/pep-0008/" rel="noopener noreferrer"&gt;PEP8&lt;/a&gt;, descubrí que para encontrar las formas correctas no había que irse muy lejos. Esto fue lo que me llevó a encontrarme con un corrector duro, pero justo, llamado Flake8.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es la PEP8?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;La PEP8 es una guía que indica las convenciones estilísticas a seguir para escribir código Python. Se trata de un conjunto de recomendaciones cuyo objetivo es ayudar a escribir código más legible y abarca desde cómo nombrar variables, al número máximo de caracteres que una línea debe tener.&lt;/p&gt;

&lt;p&gt;De acuerdo con Guido van Rossum, el código es leído más veces que escrito, por lo que resulta importante escribir código que no sólo funcione correctamente, sino que además pueda ser leído con facilidad.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ellibrodepython.com/python-pep8" rel="noopener noreferrer"&gt;Fuente&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por lo tanto, tenemos un documento que nos indica cómo escribir nuestro código de forma convencional y legible; sin tener que estar rompiéndonos la cabeza o generando nuevos estándares en el proceso.&lt;/p&gt;

&lt;p&gt;Veamos un ejemplo del mismo documento. Aquí tenemos las formas correctas de trabajar con funciones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Aligned with opening delimiter.
&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;long_function_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;var_three&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_four&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Add 4 spaces (an extra level of indentation) to distinguish arguments from the rest.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;long_function_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;var_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_three&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;var_four&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Hanging indents should add a level.
&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;long_function_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;var_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;var_three&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_four&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y aquí las formas incorrectas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Arguments on first line forbidden when not using vertical alignment.
&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;long_function_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;var_three&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_four&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Further indentation required as indentation is not distinguishable.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;long_function_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;var_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var_three&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;var_four&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Los comentarios explican las razones de cada implementación; y podemos observar que las buenas prácticas generan código más limpio y legible.&lt;/p&gt;

&lt;p&gt;Otro ejemplo interesante, las importaciones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Correct:
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="c1"&gt;# Wrong:
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="c1"&gt;# Correct:
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PIPE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando se trata de módulos separados, debemos agregar un "import" por cada uno separado por saltos de linea. Salvo que tengamos un paquete, el cual deberá importar una serie de módulos que esta vez sí serán escritos en la misma linea.&lt;/p&gt;

&lt;p&gt;Podría armar un artículo kilométrico sobre cada buena práctica que figura en la PEP8; y seguramente más de uno debe estar preocupado por la cantidad de cosas que debe tener en cuenta a la hora de escribir un buen código. No se preocupen, porque existe una solución.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¡Flake8 al rescate!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pypi.org/project/flake8/" rel="noopener noreferrer"&gt;Flake8&lt;/a&gt; es un linter de tu código. Se asienta sobre la PEP8; y esto lo convierte en la mejor opción a la hora de ahorrarnos trabajo intentando seguir las buenas prácticas desde el método tradicional.&lt;/p&gt;

&lt;p&gt;Implementamos un proyecto sencillo en Python, arrancando el entorno (VirtualEnv) en la carpeta del mismo (desde la terminal):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;python -m venv venv&lt;/p&gt;

&lt;p&gt;.\venv\Scripts\activate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Luego instalamos la dependencia de flake8&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;pip install flake8&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahora vamos a escribir un script muy sencillo, pero con todas las malas prácticas que podamos 🤣:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Max&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Max&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wrong&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Me duelen un poco los ojos. Bastante. Pidámosle a flake8 que nos ayude a mejorar este...script:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;flake8 --exclude=venv&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Agregamos el comando "exclude" para que evite evaluar el código de la carpeta "venv". Parece mentira, pero éste tiene muchísimos warnings y no nos servirá solucionarlo. Corremos el comando y nos devuelve esto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhs1sppifxuc8vlh8vp3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhs1sppifxuc8vlh8vp3w.png" alt="Flake8"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En un vistazo podemos notar que primero nos indica el archivo implicado (main.py) y luego la línea y la columna de código (2:1). Luego nos indica un código (F401) que podemos buscar en &lt;a href="https://www.flake8rules.com/" rel="noopener noreferrer"&gt;este listado de reglas de la PEP8&lt;/a&gt; si hace falta para entender a que hace referencia esta advertencia. Luego nos da una descripción del error: 'os' imported but unused. Tomé como ejemplo la primer linea para explicarlo porque todas las demás siguen el mismo patrón.&lt;/p&gt;

&lt;p&gt;Analicemos cada error, punto por punto:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;F401: Las dependencias "os" y "sys" se importaron pero no se utilizan.&lt;/li&gt;
&lt;li&gt;E401: Hay múltiples imports en una sola línea.&lt;/li&gt;
&lt;li&gt;E225: El operador del condicional no tiene espacios.&lt;/li&gt;
&lt;li&gt;W291: Luego de la variable name, hay un espacio adicional.&lt;/li&gt;
&lt;li&gt;E225: No hay espacios entre la variable name y su asignación.&lt;/li&gt;
&lt;li&gt;W292: No hay un salto de línea al final del script.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gracias a Flake8 podemos notar todos los warnings de una sola pasada. Vamos a arreglar el script y correrlo de nuevo. El objetivo es que nuestro comando no arroje ningun error, por lo tanto quede vacío. El código quedará así:&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Max&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Max&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wrong&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pueden notar un cambio muy positivo, desde la legibilidad del código hasta su acotamiento. Si nos mantenemos en los principios del PEP8 y utilizamos linters, podremos seguir las buenas prácticas sin apenas despeinarnos.&lt;/p&gt;

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

&lt;p&gt;Soy consciente de lo duro que es desarrollar correctamente: a veces la falta de tiempos y la planificación nos impulsan a resolver todo antes que dejarlo bonito. No obstante, hacer las cosas correctamente desde el principio, nos va ahorrar tener que trabajar el doble para arreglarlas en el futuro. Una guía de estilo como PEP8, conjunto de un buen linter como Flake8, nos facilitan la vida a corto, mediano y largo plazo.&lt;/p&gt;

&lt;p&gt;Si quieren ver un ejemplo más real aplicado, pueden analizar este &lt;a href="https://github.com/maxwellnewage/python-practices/commit/49c2ea25b39f8477d4ba7764ef27cf04ef0802d9" rel="noopener noreferrer"&gt;commit&lt;/a&gt; que hice a mi repositorio de prácticas en Python, donde apliqué Flake8 y cambié muchísimos scripts.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>devjournal</category>
      <category>python</category>
    </item>
    <item>
      <title>Cookie Clicker en Godot</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Thu, 08 Jun 2023 17:52:10 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/cookie-clicker-en-godot-4if9</link>
      <guid>https://dev.to/maxwellnewage/cookie-clicker-en-godot-4if9</guid>
      <description>&lt;p&gt;Antes de leer este artículo, te recomiendo pasarte por uno más introductorio donde explico las razones que me llevaron a elegir Godot como motor de juegos favorito:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/maxwellnewage" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EgXn0JEs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/practicaldev/image/fetch/s--_U09fW0y--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/285080/0b4414e1-9d08-48b5-8860-44160c1af513.png" alt="maxwellnewage"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/maxwellnewage/viaje-al-centro-de-godot-77a" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Viaje al centro de Godot&lt;/h2&gt;
      &lt;h3&gt;Maximiliano Burgos ・ Jun 5 ・ 8 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#spanish&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#godot&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#gamedev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devjournal&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Sin mas dilación, ¡comencemos!&lt;/p&gt;

&lt;h2&gt;
  
  
  Todo empieza con una galleta
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y2mvweFM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t83f39kooti1cfy0k3cc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y2mvweFM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t83f39kooti1cfy0k3cc.png" alt="Cookie Clicker Godot" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para entender Godot en su máxima expresión, decidí volver a replicar el clon de Cookie Clicker que ya había hecho en otras tecnologías.&lt;/p&gt;

&lt;p&gt;Este motor funciona por escenas, pero a diferencia de Unity, cada scene es como un objeto en si mismo, con sus propiedades y métodos. Empecé por armar una escena "Cookie" que tiene como nodo principal un Button y dentro un TextureRect, el cual contendría la imagen png de la galleta:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j5V41nSw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tge6zp2f90d2por15szx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j5V41nSw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tge6zp2f90d2por15szx.png" alt="Cookie Node" width="225" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto puede parecer extraño, pero tendrá sentido en los próximos párrafos. Al botón le armé un script para manejar los eventos del click. Vamos a ver paso a paso qué hace cada parte.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="k"&gt;onready&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cookie_texture_rect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TextureRect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;CookieTextureRect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Almaceno una referencia al TextureRect para no tener que llamarlo cada vez que lo necesito.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_ready&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;pressed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_on_pressed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;button_down&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_on_button_down&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;button_up&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_on_button_up&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este método es el primero que va a correr cuando se instancie el nodo. Las señales (signals) pressed, button_down y button_up son los eventos que nos permitirán controlar estados en el botón.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5r_okN-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0l6yms67uwlxka0pbond.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5r_okN-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0l6yms67uwlxka0pbond.png" alt="Documentación de señales" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con el método "connect" podremos crear un trigger con eventos creados y controlados por nosotros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_on_button_down&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;update_scale&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_on_button_up&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;update_scale&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_on_pressed&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;Globals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie_counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El método _on_pressed va a dispararse en el momento que se presione el botón. En este caso utilizamos una variable global definida en un archivo llamado "globals.gd":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cookie_counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;set_cookie_counter&lt;/span&gt;

&lt;span class="k"&gt;signal&lt;/span&gt; &lt;span class="n"&gt;cookie_counter_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;set_cookie_counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cookie_counter&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;new_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cookie_counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_value&lt;/span&gt;
        &lt;span class="n"&gt;cookie_counter_changed&lt;/span&gt;&lt;span class="o"&gt;.&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;new_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este caso podemos acceder a cookie_counter, como también modificarlo. Cuando cambia de valor, se llama al método setter set_cookie_counter, el cual verifica que no se trate del mismo valor; y luego de cambiarlo, llama a una señal "cookie_counter_changed". Esto lo hacemos porque en otras partes del juego estamos esperando que esta señal cambie para reescribir su valor en pantalla. De esta manera nos ahorramos tener que escribirlo constantemente, como podría ser mediante el uso del método "_process" que se ejecuta frame a frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Animación del click
&lt;/h2&gt;

&lt;p&gt;En el momento en que se presiona el botón, se llama a las señales "button_down" y "pressed". Cuando se suelta el click, se invoca "button_up". Para animar el botón, utilizo los métodos "_on_button_down" (disparador de button_down) y "_on_button_up" (disparador de button_up). Estos comparten la llamada a un método "update_scale", el cual posee la siguiente lógica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update_scale&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pressed_scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Vector2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;normal_scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Vector2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;animation_tween&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_tween&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;button_pressed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;animation_tween&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tween_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookie_texture_rect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"scale"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pressed_scale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tween&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TRANS_SINE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;animation_tween&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tween_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookie_texture_rect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"scale"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;normal_scale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tween&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TRANS_SINE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T7vd4MwD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhjypvysc2h4yjmgx5vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T7vd4MwD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhjypvysc2h4yjmgx5vn.png" alt="documentación Tween" width="800" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mi intención era animar a cookie_texture_rect (contenedor del asset de la galleta) para que se reduzca un 30% de su tamaño (vector 0.7 en x) al hacer click en el botón. Utilizo el método create_tween(), el cual me permite armar una animación con un estilo TRANS_SINE, el cual me permitirá cierta suavidad en la transición de una escala de 0.7 a 1 (pressed_scale a normal_scale y viceversa).&lt;/p&gt;

&lt;p&gt;En el caso de "button_pressed", simplemente se trata de una variable booleana (propia del botón) que devuelve el estado del mismo.&lt;/p&gt;

&lt;h2&gt;
  
  
  La tienda
&lt;/h2&gt;

&lt;p&gt;Armé otra escena para crear la tienda (shop) que listará las mejoras y permitirá comprarlas para aumentar los CpS (cookies per second). Utilicé un todo ItemList y le asigné un script. En el mismo establecí una lista de mejoras en un array de diccionarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;shop_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Click"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"cost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"give"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"M"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Cursor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"cost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"give"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"A"&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="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;A continuación, detallo cada uno de los atributos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name: nombre de la mejora.&lt;/li&gt;
&lt;li&gt;cost: costo en cookies de la compra.&lt;/li&gt;
&lt;li&gt;give: cantidad de cookies por segundo que brinda.&lt;/li&gt;
&lt;li&gt;method: La letra A indica "Auto" y M sería "Manual". En el primer caso, el atributo "give" aplica a CpS, mientras que en el segundo es el valor por click manual incrementable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Luego recorrí dicha lista y cargué un único asset para los iconos de cada item:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_ready&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResourceLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"res://granny.svg"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;shop_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;name_format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; | Valor: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; cookies | Genera &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; CpS"&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name_format&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cost"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"give"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="n"&gt;add_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalmente armé un trigger para la señal "item_selected":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_on_item_selected&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;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shop_list&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;if&lt;/span&gt; &lt;span class="n"&gt;Globals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie_counter&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cost"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;Globals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie_counter&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cost"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;Globals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookies_per_second&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"give"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Galletas insuficientes!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La función se trae el índice de la lista, el cual equivale al índice de mi array; por lo cual obtengo el item y luego valido que la cantidad de cookies sea mayor o igual al costo del item en si. Luego resto su valor (cost) y también aumento otra variable llamada cookies_per_second, la cual podemos encontrar en globals.gd nuevamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cookies_per_second&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;set_cookies_per_second&lt;/span&gt;

&lt;span class="k"&gt;signal&lt;/span&gt; &lt;span class="n"&gt;cookies_per_second_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;set_cookies_per_second&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cookies_per_second&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cookies_per_second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cookies&lt;/span&gt;
        &lt;span class="n"&gt;cookies_per_second_changed&lt;/span&gt;&lt;span class="o"&gt;.&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;cookies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como ven, la lógica es muy similar a la variable global cookie_counter.&lt;/p&gt;

&lt;h2&gt;
  
  
  La escena principal
&lt;/h2&gt;

&lt;p&gt;Ahora que tengo la escena de la tienda y la galleta, las instancio en mi escena principal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vmb8kdMf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ywpgorvnse9migq61g0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vmb8kdMf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ywpgorvnse9migq61g0g.png" alt="Game" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Utilizo un nodo VBoxContainer para manejar un label que reflejará el estado de las galletas y la instancia de la escena cookie. También tengo otro nodo igual para el título de la tienda y la lista de mejoras. Pueden notar que se encuentra vacía porque se llena en tiempo de ejecución. Finalmente tengo un HBoxContainer que contiene a los dos VBoxContainer y genera este acomodamiento horizontal de columnas.&lt;/p&gt;

&lt;p&gt;Luego tenemos un nodo Timer que contiene un script muy sencillo para actualizar cookie_counter por segundo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_on_timeout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;Globals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie_counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;Globals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookies_per_second&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El método "_on_timeout" esta conectado a una señal llamada "timeout", y se ejecuta una vez por segundo dado que lo establecimos en los parámetros del nodo (Wait Time):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JSOeEjRo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hkvdo1mugf93wxqzl6h7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JSOeEjRo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hkvdo1mugf93wxqzl6h7.png" alt="Nodo Timer" width="314" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como el atributo "Autostart" esta activo, el contador inicia apenas se activa el nodo Timer, lo cual ocurre cuando nuestra escena principal arranca, y esto es en el momento en que empieza a ejecutarse nuestro juego.&lt;/p&gt;

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

&lt;p&gt;Si llegaron hasta aca leyendo todo el artículo, los felicito por haber soportado el nivel de tecnicismos que utilicé en cada apartado. Soy consciente de que puede ser muy pesado para mucha gente, pero esto es la naturaleza de desarrollar un videojuego. &lt;/p&gt;

&lt;p&gt;No obstante, Godot simplifica y organiza como ninguno, por lo cual una vez entienden las bases y mantienen las buenas prácticas, todo se vuelve mucho más ágil.&lt;/p&gt;

&lt;p&gt;Es muy probable que me dedique a sacar más artículos sobre videojuegos y este engine, así que si disfrutaron de este contenido, ¡compártanlo para que llegue a más gente!&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>spanish</category>
      <category>godot</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Mis seguidores crecen, la comunidad toma fuerza</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Wed, 07 Jun 2023 16:23:23 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/mis-seguidores-crecen-la-comunidad-toma-fuerza-3o5</link>
      <guid>https://dev.to/maxwellnewage/mis-seguidores-crecen-la-comunidad-toma-fuerza-3o5</guid>
      <description>&lt;p&gt;Hoy traigo una gran noticia sobre el crecimiento constante de mi blog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fy834rs3s7yexb299b20d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fy834rs3s7yexb299b20d.png" alt="dev.to followers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¡Ya son 706 seguidores!&lt;/strong&gt; Quiero agradecerles enormemente por este gran logro, el cual se nota en las visitas que tiene cada artículo. Por eso, les voy a comentar tanto para los nuevos como los más veteranos, la historia detrás de estas publicaciones y el futuro del blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bienvenidos al Maxiverso
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;En principio la idea era fusionar mi nombre con la palabra "universo", pero suena horrible. Sigo trabajando en el tema, no me reporten.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Este blog es, en realidad, la continuación de un proyecto que venía trabajando en Medium, otra plataforma de blogging excelente pero con limitaciones para aquellos que quieren consumir contenido gratuito.&lt;/p&gt;

&lt;p&gt;Previo a DEV.to, desarrollé mi propio blog con su respectivo dominio y duró unos meses en la nube. Pero no tuvo mucho éxito: me llevaba mucho trabajo mantenerlo, y el tráfico era apenas aceptable. Además pagaba mes a mes un servicio de AWS llamado LightSail, porque tenía un WordPress montado y era la solución más económica. Pero aportar a la comunidad en tiempo y dinero sin recibir nada a cambio, era una locura.&lt;/p&gt;

&lt;p&gt;Así llegué a esta increíble comunidad, DEV.to. Ya la tenía en el radar hace un tiempo, pero me preocupaba no poder establecer mi ecosistema porque no existían secciones como tal. Luego de meditar y rearmar mi estructura de cada artículo, migré todo lo que consideraba relevante de Medium a DEV.to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Series, muchas series
&lt;/h2&gt;

&lt;p&gt;Esta plataforma tiene dos características que, bien utilizadas, pueden mejorar cualquier artículo que escribas: los tags (o etiquetas) y las series.&lt;/p&gt;

&lt;p&gt;En el primer caso, se trata de tags como los que utilizamos en Twitter para relacionar un tema con nuestro tweet, pero aquí es mucho más importante. Los tags de DEV.to &lt;strong&gt;son las categorías en si&lt;/strong&gt;. Esto implica que si estás escribiendo un artículo sobre Python, deberías utilizar el tag correspondiente para &lt;a href="https://dev.to/t/python"&gt;aparecer&lt;/a&gt; en la sección de este lenguaje. Por otro lado, los que escribimos en español (dado que la comunidad fue pensada inicialmente para contenido en inglés) tenemos nuestro propio tag. Podés verlo &lt;a href="https://dev.to/t/spanish"&gt;aquí&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En el caso de las series, se trata de una forma de agrupar artículos por "episodios". Imaginalo como un podcast, donde cada entrega sea un capítulo dentro de Spotify. Esto es lo mismo, y fue la razón que facilitó toda la migración de las categorías de mis artículos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mis series más importantes
&lt;/h2&gt;

&lt;p&gt;A este punto quería llegar: a medida que fui creciendo en contenido y gente interesada en el mismo, armé unas series especializadas en cada tema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/maxwellnewage/series/23219"&gt;Opinión&lt;/a&gt;: Se trata de un conjunto de artículos que cuentan experiencias que tuve en sistemas y en mi vida personal; pero siempre desde la mirada técnica.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/maxwellnewage/series/21362"&gt;Diario de Python&lt;/a&gt;: Los diarios son mis series favoritas, porque me permiten expresar todas las sensaciones que voy experimentando a medida que aprendo algo nuevo o emprendo proyectos interesantes. En este caso, se trata de Python.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/maxwellnewage/series/20920"&gt;Diario de Kotlin&lt;/a&gt;: Probablemente no actualice esta serie, porque pertenece a una época donde trabajaba activamente con Android y Kotlin. No obstante, lo dejo como un buen material de estudio para los que quieran empezar en este mundo.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/maxwellnewage/series/20919"&gt;Patrones de Diseño&lt;/a&gt;: Esta serie se centra en explicar distintos patrones de diseño aplicados desde la teoría. Es probable que en el futuro, cuando empecemos las prácticas, se realicen en Python.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Mi idea central con este artículo es empezar a darle cierta forma al ecosistema que estoy armando en torno al contenido generado. Pero también quiero que vean todo lo que ya existe, porque se que los artículos nuevos tienden a hacerle sombra a los viejos con el tiempo. Quiero generar cierta atemporalidad, dado que todos mis artículos se pueden leer en cualquier momento del año, o en su defecto, de la década.&lt;/p&gt;

&lt;p&gt;¡Nos vemos en los siguientes!&lt;/p&gt;

</description>
      <category>news</category>
      <category>discuss</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Viaje al centro de Godot</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Mon, 05 Jun 2023 15:33:26 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/viaje-al-centro-de-godot-77a</link>
      <guid>https://dev.to/maxwellnewage/viaje-al-centro-de-godot-77a</guid>
      <description>&lt;p&gt;Antes de empezar, debo aclarar que el nombre del título hace referencia al libro &lt;a href="https://es.wikipedia.org/wiki/Viaje_al_centro_de_la_Tierra"&gt;Viaje al centro de la Tierra&lt;/a&gt; de Julio Verne.&lt;/p&gt;

&lt;h2&gt;
  
  
  Punto de inflexión
&lt;/h2&gt;

&lt;p&gt;El mes pasado estuve trabajando a fondo en desarollar mis habilidades en React, Tauri, Rust, entre otros. El clicker de pre-proyecto &lt;a href="https://dev.to/maxwellnewage/hice-un-clon-de-cookie-clicker-en-react-229f"&gt;salió bien&lt;/a&gt;, pero cuando me senté a armar el proyecto real (CraftClicker) empecé a notar ciertas carencias.&lt;/p&gt;

&lt;p&gt;La idea de progresión en mi clicker iba de la mano de construir un pueblo, consecuencia de vender recursos y crafteos y comprar edificios.&lt;/p&gt;

&lt;p&gt;En el momento en que me puse a trabajar en el proyecto, me di cuenta de la complejidad de capas que necesitaba: generación de terrenos, tilesets, drag and drop, entre otros tantas características que me llevarían a la locura si intentaba trabajar sobre un sistema de etiquetas divs y componentes en React.&lt;/p&gt;

&lt;p&gt;Este fue el resultado al que llegué antes de desistir de la tecnología:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eFNos5cS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/reytxbja8xyan7juhh0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eFNos5cS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/reytxbja8xyan7juhh0p.png" alt="React Game" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La barra de abajo permitiría comprar edificios nuevos, mientras que arriba tendría la ciudad (o pueblo) que podría editar a mi antojo.&lt;/p&gt;

&lt;p&gt;Luego de meditar un buen tiempo, me di cuenta que iba a luchar más por crear componentes que no fueron pensados para juegos que desarrollar el proyecto en sí. Algunos pensarán: muchos desarrolladores crearon herramientas de cero en lenguajes que no estaban pensados para eso, y les fue bien. Lo cual es cierto, pero no todos estamos dispuestos a dedicar un volumen tan alto de tiempo y energía a una tarea de esa magnitud.&lt;/p&gt;

&lt;p&gt;Ya con la decisión tomada, ahora debía trazar el nuevo camino: no volvería a Unity porque nunca me gustó su sistema de componentes y la facilidad con que un proyecto puede terminar volviéndose muy dificil de mantener por las libertades de poner scripts en cualquier lado. Así que la ruta final sería Godot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oh dios mío, no de nuevo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5WqAHwq0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ir2r848vv4kg6cmvtza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5WqAHwq0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ir2r848vv4kg6cmvtza.png" alt="Not Again meme" width="299" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No es la primera vez que me lanzo a los brazos de &lt;a href="https://godotengine.org/"&gt;Godot Engine&lt;/a&gt; buscando refugio en una lluvia constante de motores que aparecen cada año. La variedad es buena, pero puede ser un infierno si queremos probar todo. Lo digo, especialmente, por experiencia propia.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitch.tv/marianorgd"&gt;Marian&lt;/a&gt;, uno de los dev en Godot más experimentado que conozco (al momento de la salida de esta publicación está trabajando en un emulador de NES) fue víctima de soportarme noches enteras armando prototipos de juegos que nunca vieron la luz. Recomiendo seguirlo porque nunca conocí una persona con más paciencia para enseñar y ayudar.&lt;/p&gt;

&lt;p&gt;Por eso cuando le expliqué la semana pasada que volvía al ruedo, estoy seguro que por dentro pensó exactamente esto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EdDu486R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3kh1f4o6cz6g4mfzepwa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EdDu486R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3kh1f4o6cz6g4mfzepwa.png" alt="oh shit here we go again" width="498" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En este momento muchos se estarán preguntando: ¿pero por qué lo dejaste antes? La respuesta es confusa, incluso para mí: nunca me llevé bien con el apartado artístico y me desmotivaba desarrollar algo mediocre. Conozco mucha gente que le pasa, incluso tengo un amigo que contrata diseñadores que le hacen todos los assets antes de empezar incluso el prototipo, porque cuando desarrolla se motiva al ver que su forma estética sigue los lineamientos que tenía en su idea original.&lt;/p&gt;

&lt;p&gt;Por otro lado, en el pasado no me convencía GDScript (lenguaje de programación basado en Python, oficial del motor) porque justamente no sabía nada de Python. También tenía cierto rechazo a la física y las matemáticas, lo cual fue cambiando cuando me metí con &lt;a href="https://dev.to/maxwellnewage/python-y-datos-un-viaje-de-ida-437"&gt;análisis de datos&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Pero qué cambió ahora?
&lt;/h2&gt;

&lt;p&gt;Bueno, en principio hay un motivante financiero: compré la licencia de 100usd en Steam ($20.000ars en su momento), lo cual como argentino me duele bastante. Esto implica que si no publico un juego, habré perdido dinero.&lt;/p&gt;

&lt;p&gt;Luego está el legendario objetivo incumplido: desde que empecé a escribir mis primeras líneas de código, quiero desarrollar juegos. Las vueltas de la vida me llevaron a estudiar y trabajar en otros ámbitos, pero como expliqué en otro &lt;a href="https://dev.to/maxwellnewage/creo-que-me-converti-en-un-desarrollador-en-react-y-typescript-2fkf"&gt;artículo&lt;/a&gt;, en cada tecnología nueva que asimilo a mi vida, intento crear uno o más videojuegos. Pero siempre tuve cierto miedo a sacar algo real: los bugs, las mejoras constantes, los consumidores que a la mínima te bajan la calificación si algo no les gusta, el marketing y la publicidad, el tiempo invertido y muchos otros factores de peso, eran suficientes razones (o excusas) para evitar publicar algo.&lt;/p&gt;

&lt;p&gt;Y después falleció Lupe, mi chihuaha de 2 años de edad. Y fue la tragedia de lo cambió todo.&lt;/p&gt;

&lt;h2&gt;
  
  
  La vida es una función rand() con seeds aleatorias
&lt;/h2&gt;

&lt;p&gt;Lupe era la perra más saludable que pueden imaginar. Se dedicaba a romper prejuicios como que los chihuahas no podían subir escaleras; comía de todo y no se enfermaba; tenía un carácter amigable y nunca destrozó nada.&lt;/p&gt;

&lt;p&gt;Pero un día, tiramos una palmera de esas enanas que vienen de Japón, y cayeron unas semillas que nunca se podían acceder, porque pertenecían a la parte de arriba, donde crecían sus nuevas hojas. Resulta que su ingestión provocaba necrosis y fallos digestivos. Y Lupe, como siempre, se llevaba cualquier cosa que pareciera un juguete a sus refugios repartidos por toda la casa.&lt;/p&gt;

&lt;p&gt;Y, como quien tira un dado, ese evento tan fortuito, tan aleatorio, se llevó a nuestra cachorra de 2 años de edad (los chihuahas tiene una esperanza de vida de 14 años). Un martes estaba jugando con ella, y al siguiente estaba usando una pala, con una caja al lado.&lt;/p&gt;

&lt;p&gt;En una semana, se había perdido la luz de la casa. En algún lugar, se ejecutó una función rand() y nos tocó perderlo todo.&lt;/p&gt;

&lt;p&gt;Ahí fue cuando tuve una especie de revelación: me estoy preocupando por cosas que no puedo controlar, además de que realmente no tengo nada que perder. Cualquier asunto, incluso el trabajo, pasó a segundo lugar. El grado de importancia y prioridad de todo lo que no estaba relacionado con ese momento que estaba pasando, decrementó completamente. Porque si el universo funciona por eventos aleatorios, no existe algo como una balanza divina. No hay un sistema de castigos y recompensas; y probablemente ni siquiera exista un sistema como tal. Intentamos dar sentido a cosas que no lo tienen, y creamos nuestro propio sistema con sus reglas. Mi objetivo final fue destruir toda la estructura, y empezar de nuevo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entre la planificación y la locura
&lt;/h2&gt;

&lt;p&gt;Asumir que la mayoría de mis preocupaciones carecían de valor, me quitó el miedo a emprender proyectos. Quizá lance el juego y no tenga éxito; pero no importaba porque lo había lanzado. Mis logros, en realidad, se establecían bajo mi criterio: &lt;a href="https://www.udemy.com/course/desarrollo-de-sitios-web-con-python-3-con-django/?referralCode=A491B0944C634BFAA48C"&gt;publicar el curso de Python con Django&lt;/a&gt; fue un logro en si mismo, aunque la gente no lo compre tanto. Disfruté el proceso de hacerlo sin pensar tanto en el futuro del mismo.&lt;/p&gt;

&lt;p&gt;Por lo tanto, publicar un videojuego pasó a ser un objetivo obligatorio: otra forma de demostrarme a mi mismo que no importaban los resultados, sino el hecho de lanzar este, y quizá otros juegos más. Cerrar el ciclo del "quiero y no puedo".&lt;/p&gt;

&lt;p&gt;Mi plan inicial mutó constantemente, a tal punto de que ya lo estoy considerando como una parte más del proceso: ahora el clicker pasó a ser un RPG de un hombre que debe ganar dinero desde cero (a tal punto de dormir en los bancos de la plaza) hasta volverse un magnate que tiene varias empresas a su cargo. Planifico como un loco porque un cambio puede significar la reconstrucción casi completa de la estructura. ¿Por qué? porque puedo, y si mañana perezco de una forma extremadamente aleatoria (algo como atragantarme con un te de burbujas en el Barrio Chino de Belgrano, CABA), todo valió la pena porque hice lo que quería desde el principio, sin restricciones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Etapa de aprendizaje
&lt;/h2&gt;

&lt;p&gt;Creo haber entrado en esta zona más de tres o cuatro veces en lo que va del año, pero prometo que esta vez será definitivo. Para aprender Godot (ya en su versión 4), empecé con este youtuber que descubrí y no puedo dejar de ver en cada video que lanza:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/L3pFEk1HPCQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Me gusta como enseña, y la verdad tiene una calidad altísima que envidio sanamente (o no) en cada uno de sus videos. &lt;/p&gt;

&lt;p&gt;Por otro lado, decidí armar el mismo clon de Cookie Clicker que hice en React, pero en Godot. Les dejo el &lt;a href="https://github.com/maxwellnewage/godot-cookie-clicker"&gt;repositorio&lt;/a&gt; que armé y sigo manteniendo, pero seguramente en el próximo artículo explore más a fondo cada detalle del armado. Nuevamente, gracias Marian por despejarme las dudas de los nodos correctos para crearlo.&lt;/p&gt;

&lt;p&gt;En paralelo, estoy siguiendo otro curso para armar un RPG tipo Zelda:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/0mUoRdYe0s4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Este me sirve para complementar características fundamentales de Godot tales como Tileset, Tilemaps, animaciones, sprites, UI, controles, entre otros. Por supuesto, a medida que voy realizando el tutorial, también estoy publicando los cambios en un &lt;a href="https://github.com/maxwellnewage/godot-arpg-tutorial"&gt;repositorio de GitHub&lt;/a&gt;. No estoy copiando todo como en el curso, sino que me voy tomando atribuciones en ciertas partes por otros videos o documentación complementarios.&lt;/p&gt;

&lt;p&gt;Otra herramienta interesante &lt;a href="https://gdquest.github.io/learn-gdscript/"&gt;es esta web&lt;/a&gt;, la cual te enseña visualmente GDScript. Todavía no me metí de lleno, pero planeo hacerlo esta semana. Si no tienen nociones en programación, es un punto de entrada excelente antes de meterse con el engine de Godot.&lt;/p&gt;

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

&lt;p&gt;Espero que sepan disculpar mis cambios constantes de tecnologías, pero tengan en cuenta que es probable que les pase a ustedes también, si es que no lo están sufriendo ahora mismo. &lt;/p&gt;

&lt;p&gt;Una idea por si misma no tiene valor alguno, sino que su ejecución y la conversión a algo "tangible" es lo que realmente le da un significado.&lt;/p&gt;

&lt;p&gt;Mi idea inicial del juego cambia a medida que voy aprendiendo nuevas cosas de cada tecnología, pero va tomando cierta forma final. Este proceso de iteración es natural, y si ustedes están pasando por algo similar, les aconsejo que no se frustren y continúen iterando hasta llegar al proceso final.&lt;/p&gt;

&lt;p&gt;Hoy Godot es la solución a mi proyecto, y planeo sacarle mucho jugo en los siguientes meses. En los próximos artículos hablaremos mucho de este motor que esta conquistando devs que antes no se movían de Unity.&lt;/p&gt;

&lt;p&gt;¡Nos vemos en el próximo artículo!&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>godot</category>
      <category>gamedev</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Hice un clon de Cookie Clicker en React</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Mon, 29 May 2023 15:36:01 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/hice-un-clon-de-cookie-clicker-en-react-229f</link>
      <guid>https://dev.to/maxwellnewage/hice-un-clon-de-cookie-clicker-en-react-229f</guid>
      <description>&lt;p&gt;Antes de empezar a leer este artículo y por motivos de contexto, te recomiendo leer la historia que me llevó a terminar tomando las decisiones para crear este clon. Lo podés encontrar acá:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/maxwellnewage" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EgXn0JEs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/practicaldev/image/fetch/s--_U09fW0y--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/285080/0b4414e1-9d08-48b5-8860-44160c1af513.png" alt="maxwellnewage"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/maxwellnewage/creo-que-me-converti-en-un-desarrollador-en-react-y-typescript-2fkf" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Creo que me convertí en un desarrollador en React y Typescript&lt;/h2&gt;
      &lt;h3&gt;Maximiliano Burgos ・ May 16 ・ 5 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#spanish&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#typescript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Aclaro que este artículo va a profundizar mucho en los aspectos técnicos que me llevaron a armar el proyecto, por lo que sería recomendable que tengas nociones básicas de desarrollo (web preferentemente) para entenderlo.&lt;/p&gt;

&lt;p&gt;Como he mencionado anteriormente, pueden encontrar el repositorio con el código completo &lt;a href="https://github.com/maxwellnewage/react-clicker"&gt;aquí&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Primeras decisiones de arquitectura
&lt;/h1&gt;

&lt;p&gt;Para el que no lo sepa, Cookie Clicker es un juego desarrollado puramente en web, con HTML para dar la estructura, CSS para los estilos y finalmente Javascript para la parte lógica de programación. Seguramente tenga algunas librerías que desconozco, pero en escencia, esos son sus pilares principales.&lt;/p&gt;

&lt;p&gt;Desarrollar un juego web otorga ciertas facilidades con respecto a la adaptabilidad, dado que la parte responsiva, por ejemplo, nos resuelve que éste sea compatible en múltiples resoluciones.&lt;/p&gt;

&lt;p&gt;Por otro lado, la curva de aprendizaje de las tecnologías web (en general) es bastante baja: en un mes ya estás dominando los fundamentos de JS, por ejemplo. Por supuesto, hay conceptos más complejos como patrones reactivos, infraestructura o incluso maquetar una web y que todo funcione sin romperse en múltiples navegadores, sistemas operativos y versiones.&lt;/p&gt;

&lt;p&gt;Pero a fin de cuentas, cualquier tecnología explorada en profundidad se vuelve compleja: hay años, incluso décadas de desarrollo detrás de cada una. Es normal que vos, Jose Perez, sentado en tu PC, no logres entender por donde empezar y qué terminar siendo ante la gran cantidad de información que ronda por ahí.&lt;/p&gt;

&lt;p&gt;Por eso hay que sentarse y trabajar en el stack de tecnologías acorde a las necesidades que tengamos en base a un proyecto, o una serie de ellos. En este caso, consideré que seguir los pasos de Cookie Clicker era lo más acertado.&lt;/p&gt;

&lt;p&gt;Por supuesto, estamos hablando de un videojuego que lleva más de una década en desarrollo: las formas de programar cambiaron mucho desde entonces, y la idea era quedarse con la cáscara, pero descartar la yema del huevo.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tecnologías involucradas
&lt;/h1&gt;

&lt;p&gt;Por esta razón, este juego y los siguientes van a apoyarse en desarrollos web, pero con algunas librerías adicionales.&lt;/p&gt;

&lt;p&gt;Por un lado tenemos a &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; y &lt;a href="https://www.typescriptlang.org/"&gt;Typescript&lt;/a&gt;, conjunto de &lt;a href="https://vitejs.dev/"&gt;ViteJS&lt;/a&gt; para inicializar el proyecto. En realidad esto último es una mentira a medias, porque el que creará todo será &lt;a href="https://tauri.app/"&gt;Tauri&lt;/a&gt;, el cual se apoya en Vite para concluir el armado, con configuraciones adicionales de &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;React sigue el paradigma reactivo, lo cual nos permite trabajar con componentes independientes que se pueden comunicar entre ellos y reaccionar mediante eventos. Este tipo de comportamientos esta reflejado en cualquier motor de desarrollo de juegos que utilicemos, tal como Unity, Unreal o Godot, por nombrar algunos.&lt;/p&gt;

&lt;p&gt;Typescript es un "must", porque nos da una estructura sólida y evita el tipado dinámico. En un ecosistema donde van a existir muchísimos tipos de datos interactuando mediante componentes, es necesario establecer orden y evitar que un entero ocupe el lugar de un string, y viceversa.&lt;/p&gt;

&lt;p&gt;Tauri es mi alternativa a ElectronJS. &lt;a href="https://dev.to/maxwellnewage/un-pequeno-paseo-por-rust-4lko"&gt;Dediqué unas dos semanas a Rust para entenderlo&lt;/a&gt;, aunque no es necesario que hagas lo mismo que yo. Podés compilar un ejecutable en utilizando esta librería simplemente creando el proyecto web que necesites; incluso migrando uno. Yo lo aprendí por cualquier eventualidad, o si en algun momento quería armar algun complemento para Tauri.&lt;/p&gt;

&lt;h1&gt;
  
  
  Estructura de componentes
&lt;/h1&gt;

&lt;p&gt;En principio tenemos el típico main.tsx de toda la vida, envolviendo al componente App:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;render&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;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&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;App&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;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el mismo, también estoy incluyendo la librería de &lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bootstrap/dist/css/bootstrap.min.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro del componente App, tengo varias cosas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&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;cookieAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCookieAmount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInventory&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InventoryType&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;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;CookieContext&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;cookieAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCookieAmount&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InventoryContext&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;inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInventory&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'d-flex flex-column min-vh-100 justify-content-center align-items-center'&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"row"&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"col"&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;Cookie&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"col"&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;Shop&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;&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;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="nc"&gt;InventoryContext&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;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CookieContext&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;Por un lado, utilizo un useState para trabajar con la cantidad de galletas en el juego. Estas requieren un manejo global, por lo tanto tengo un CookieContext encargado de llevarlo a cualquier componente que lo requiera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CookieContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CookieProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;cookieAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;setCookieAmount&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;También tengo un useState para el inventario, responsable de almacenar las mejoras compradas en el juego:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInventory&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InventoryType&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tal como pasa con las galletas, también tiene su contexto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;InventoryContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InventoryProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;setInventory&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;La única diferencia es que maneja un tipo específico para manejar los items del inventario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;InventoryType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ItemType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;Luego, dentro del diseño en dos columnas, tenemos el componente de la galleta y la tienda de mejoras.&lt;/p&gt;

&lt;h1&gt;
  
  
  Componente Cookie
&lt;/h1&gt;

&lt;p&gt;En el caso de la galleta en si, se maneja un estado para generar la animación de click que tiene el juego original:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isAnimating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsAnimating&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;incrementCookie&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isAnimating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setIsAnimating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;setTimeout&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="nx"&gt;setIsAnimating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;incrementCookie&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por otro lado, armamos un estado para manejar el valor de un click manual. Por defecto es 1, pero a medida que compramos mejoras de clicks, va incrementando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;clickerUpgrade&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setClickerUpgrade&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estas mejoras las traemos en el momento en que se genera el componente así como también en cada cambio del inventario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;useEffect&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="nx"&gt;setClickerUpgrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getTotalGiveInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ItemMethodEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;M&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="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Puede que la función &lt;em&gt;getTotalGiveInventory&lt;/em&gt; te resulte desconocida, y es porque armé un hook personalizado para manejar el inventario con métodos específicos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTotalGiveInventory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useInventory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este caso particular, obtenemos el total de clicks mejorados por el tipo de mejora:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTotalGiveInventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ItemMethodEnum&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;inventoryByMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;method&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;inventoryByMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;accumulator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inv&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;return&lt;/span&gt; &lt;span class="nx"&gt;accumulator&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;give&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;0&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;Para entender esto, necesito explicarles los dos tipos que manejo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mejoras manuales (ItemMethodEnum.M): son aquellas que se otorgan cuando hacemos click en la galleta.&lt;/li&gt;
&lt;li&gt;Mejoras automáticas (ItemMethodEnum.A): corren cada segundo, se les suele llamar "autoclicks".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por otro lado, para comprender los cálculos involucrados tanto en filter como reduce, les muestro dos mejoras que existen en la tienda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ItemType&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HiCursorClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;give&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ItemMethodEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;M&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cursor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BsHandIndexThumb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;give&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ItemMethodEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;A&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;El atributo &lt;em&gt;give&lt;/em&gt; es el valor que se sumariza en nuestra función según el tipo de item (manual o automático). A continuación, les muestro las estructura de ItemType para ilustrar mejor este ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ItemType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IconType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;give&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ItemMethodEnum&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;Este comportamiento se refleja en el momento de llamar a la función &lt;em&gt;incrementCookie&lt;/em&gt; del componente Cookie, cuando actualizamos el valor de CpS (cookies por click):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;setCookieAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookieAmount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;clickerUpgrade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el caso del manejo de CpS automáticos, tenemos al componente CookieCounter, el cual tiene un comportamiento similar a Cookie:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;useEffect&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;intervalId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setInterval&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="nx"&gt;setCookieAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookieAmount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;giveInventory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;intervalId&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="nx"&gt;cookieAmount&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como cookieAmount cambia constantemente, esto entra en un bucle infinito donde siempre estan aumentando las galletas. El que define cuántos deben ser los CpS automáticos es otro useEffect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;useEffect&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="nx"&gt;setGiveInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getTotalGiveInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ItemMethodEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;A&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="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y finalmente en la parte visual, hacemos un redondeo porque a veces las compras o ventas pueden generar decimales:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookieAmount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; galletas
    &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;h2&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;giveInventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; g/s&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Componente Shop
&lt;/h1&gt;

&lt;p&gt;Este componente es muy sencillo porque contiene la lista de mejoras, pero en otro componente distinto, con el fin de separar las responsabilidades de cada uno.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Shop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&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="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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-center"&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;Tienda&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"row"&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;ShopItemList&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;&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;p&gt;Con ShopItemList ocurre algo similar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ShopItemList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&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="nx"&gt;itemList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ShopItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;itemList&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recorremos una lista de items que se carga desde un archivo que se encuentra en data/shop_items, el cual se pudo observar cuando estudiábamos el manejo de mejoras manuales y automáticas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;items&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;../../data/shop_items&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;p&gt;Por cada item de la lista, renderizamos un componente ShopItem que se lleva por parámetro el item en sí. En este componente, hay varios aspectos observables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemSellingCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La constante itemSellingCost nos permite vender el item a la mitad del costo de compra. Es una forma sencilla que encontré para definir valores de venta.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getItemInventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAmountItemInventory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useInventory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Volvemos a hacer uso del hook que definimos para inventory, pero esta vez nos llevamos &lt;em&gt;getItemInventory&lt;/em&gt; para obetener un item del inventario, y &lt;em&gt;setAmountItemInventory&lt;/em&gt; para modificar la cantidad del item existente. Para entender esto en mayor detale, podemos ver la estructura de un item en el inventario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;InventoryType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ItemType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;Podemos observar que &lt;em&gt;shopItem&lt;/em&gt; es de tipo ItemType, lo cual nos indica que podemos tener un item que sale de shop_items. Por otro lado, tenemos un campo numérico &lt;em&gt;amount&lt;/em&gt;, el cual va a manejar la cantidad de "shopItem" que poseemos. Gracias Typescript por tanto, y perdón por tan poco.&lt;/p&gt;

&lt;p&gt;Siguiendo con la exploración de nuestro componente ShopItem, tenemos un useEffect que va a obtener el item del inventario y luego setearlo en un useState para que se actualice en tiempo real:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;useEffect&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;itemInventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getItemInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;setItemAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemInventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&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="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego, en el maquetado del item, tenemos dos botones (para compra y venta) y cada uno va a la misma función &lt;em&gt;transaction&lt;/em&gt;, la cual maneja un action "B" (buy, compra) y "S" (sell, venta):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"col"&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;button&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-success"&lt;/span&gt;
    &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cookieAmount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h5&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;shopItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cost&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;h5&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;button&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;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ms-3 btn btn-danger"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;S&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h5&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;itemSellingCost&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;h5&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;button&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro de la función transaction, validamos dos casos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;En el caso de la compra, restamos la cantidad de galletas al costo del item (la validación de la cantidad que podemos comprar está determinada por el disabled del mismo botón) y luego llamamos al método &lt;em&gt;setAmountItemInventory&lt;/em&gt;, que se encargará de manejar el agregado o modificación del item en el inventario.&lt;/li&gt;
&lt;li&gt;En el caso de la venta, sumamos a la cantidad de galletas el costo del item dividido dos, como vimos al principio.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;S&lt;/span&gt;&lt;span class="dl"&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="o"&gt;=&amp;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="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B&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="nx"&gt;setCookieAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookieAmount&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setAmountItemInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setCookieAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookieAmount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;itemSellingCost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setAmountItemInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shopItem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;S&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con esto tenemos todo el manejo del juego resuelto, dado que &lt;em&gt;cookieAmount&lt;/em&gt; es parte de CookieContext, así que modifica las galletas globalmente. Y en el caso del inventory, nuestro hook se encarga de modificar mediante determinados métodos la cantidad de elementos en el inventario.&lt;/p&gt;

&lt;h1&gt;
  
  
  Compilación
&lt;/h1&gt;

&lt;p&gt;Para compilar este juego en un ejecutable, gracias a Tauri, no nos lleva más que un simple comando en consola:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm run tauri dev&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Y lograremos obtener una ventana como esta:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eHHQ169r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9utqx0tzo1kvrje1yf4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eHHQ169r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9utqx0tzo1kvrje1yf4x.png" alt="Proyecto Tauri" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusiones
&lt;/h1&gt;

&lt;p&gt;Este juego me desafió en muchos aspectos, desde lo técnico hasta el diseño y maquetado de cada aspecto visual. Me permitió fortalecerme en tecnologías que ya conocía, así como también aprender nuevas que no esperaba introducir a mi stack este año, como Rust.&lt;/p&gt;

&lt;p&gt;Recomiendo plantearse proyectos como éste cuando quieran dominar tecnologías nuevas, porque no solo es entretenido, sino también extremadamente complicado (se tenía que decir, y se dijo). Esa dificultad es la que realmente va a marcar la diferencia entre seguir un tutorial, y hacer algo realmente desde cero.&lt;/p&gt;

&lt;p&gt;Y, como consejo final: terminar el proyecto, no dejarlo a medias, es la parte más importante de este proceso.&lt;/p&gt;

&lt;p&gt;¡Nos vemos en los próximos artículos! &lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>react</category>
      <category>spanish</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Un pequeño paseo por Rust</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Sat, 27 May 2023 23:15:58 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/un-pequeno-paseo-por-rust-4lko</link>
      <guid>https://dev.to/maxwellnewage/un-pequeno-paseo-por-rust-4lko</guid>
      <description>&lt;p&gt;Antes de comenzar, quiero aclarar que no es para nada sencillo escribir casi a diario. Cada vez que lo intento, termino inmerso en una nueva investigación que me lleva semanas, o incluso un mes entero. Este fue el caso de Rust.&lt;/p&gt;

&lt;h1&gt;
  
  
  ¿Pero cómo llegué acá?
&lt;/h1&gt;

&lt;p&gt;Es una pregunta que me hago probablemente desde mi nacimiento, pero en este caso fue un poco más extraño: si leyeron &lt;a href="https://dev.to/maxwellnewage/creo-que-me-converti-en-un-desarrollador-en-react-y-typescript-2fkf"&gt;mi artículo anterior&lt;/a&gt;, mi plan en muy resumidas cuentas, era aprender React y TypeScript. Mi felicidad estaba llegando, dado que terminaría mi fase de estudiante eterno para introducirme finalmente en el momento de empezar el bendito proyecto del clicker, hasta que llegó esto:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/XYH6_GV5KQ0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Tauri es un duro competidor de ElectronJS, y da bastante miedo: he visto varias comparativas y supera con creces a éste último. El punto más fuerte de Tauri es que compila en código de máquina; no como Electron que hace una especie de paquete con NodeJS y arma un ejecutable híbrido, además de ensuciar bastante el proyecto. Pueden encontrar mis repositorios con el clicker implementado en &lt;a href="https://github.com/maxwellnewage/react-clicker"&gt;Electron&lt;/a&gt; y &lt;a href="https://github.com/maxwellnewage/tauri-clicker"&gt;Tauri&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Encontré en Tauri una solución más limpia y robusta, pero existía un pequeño (gran) detalle: estaba desarrollada en Rust.&lt;/p&gt;

&lt;h1&gt;
  
  
  Otro viaje de aprendizaje, el último, espero.
&lt;/h1&gt;

&lt;p&gt;En el mundo del desarrollo, Rust es sinónimo de un "señor lenguaje de programación". La gente lo adora, especialmente en las vastas tierras de StackOverflow. Siempre me dió cierta curiosidad, pero en esas épocas mi objetivo era especializarme en Android y Kotlin.&lt;/p&gt;

&lt;p&gt;Si bien se puede desarrollar una aplicación web con Tauri, y dejar que sus componentes hagan su trabajo como una caja negra; mi necesidad de saberlo todo no me dejaba en paz: tenía que conocer Rust, de la misma forma que todos los conductores deberíamos saber mecánica para entender cómo funciona un vehículo por dentro.&lt;/p&gt;

&lt;p&gt;Como siempre, me dediqué a buscar artículos y videos de youtube. Dejo una lista de aquellos que me parecieron más interesantes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=-anm93UDkTk"&gt;Por qué tienes que aprender Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=-anm93UDkTk"&gt;Rust esta mejorando el desarrollo web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=lzKeecy4OmQ"&gt;Rust 101 Crash Course&lt;/a&gt;: Este recurso en particular me encantó, nunca vi alguien que explicara tan bien los conceptos.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://empresas.blogthinkbig.com/rust-errores-programacion-uso-memoria/"&gt;¿Salvará Rust el mundo? Parte 1&lt;/a&gt;: En el final del artículo esta el enlace a la segunda parte.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/shorts/QPhbR7oIOq8"&gt;¿Qué es Rust?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Luego de estudiar un par de días, me di cuenta que Rust era extremadamente difícil.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rust es difícil
&lt;/h1&gt;

&lt;p&gt;Me encontré en una situación compleja: Rust se me antojaba esotérico a ratos, con una sintaxis muy propia del lenguaje que no había visto desde que dejé de programar en C o C++. Por ejemplo, esto es un "Hello World" con variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;prints&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Tomas"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Max"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&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;En este caso, "let mut" define a &lt;em&gt;name&lt;/em&gt; como una variable mutable, y "&amp;amp;str" es algo parecido a un tipo String. Luego, "println!" tiene un signo de admiración porque se trata de una macro (la cual es distinta y parecida a una función, al mismo tiempo) y debemos utilizar llaves para representar valores por cómo funcionan los tipos.&lt;/p&gt;

&lt;p&gt;Vengo de lenguajes de tipado dinámico (salvando quizá, Kotlin y Java), por lo cual encontrarme con lo que vamos a llamar "tipado muy fuerte", que al mínimo pasaje incorrecto deja de compilar, fue una pesadilla inicialmente.&lt;/p&gt;

&lt;p&gt;La curva continuó subiendo a medida que aprendí sobre otros conceptos, como operadores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Addition, Subtraction, and Multiplication&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"1 + 2 = {} and 8 - 5 = {} and 15 * 3 = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Integer and Floating point division&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"9 / 2 = {} but 9.0 / 2.0 = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;9.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"9 / 2 = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;9f32&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2f32&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;Donde una división de enteros no podía generar un flotante, entonces necesitabas definirlo previamente (9 flotante de 32 bits).&lt;/p&gt;

&lt;p&gt;Por otro lado, las tuplas eran similares a Python, pero muy extrañas en su definición:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;tupla&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Tuple of length 3&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tuple_e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'E'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Use tuple indexing and show the values of the elements in the tuple&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"Is '{}' the {}th letter of the alphabet? {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tuple_e&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tuple_e&lt;/span&gt;&lt;span class="na"&gt;.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tuple_e&lt;/span&gt;&lt;span class="na"&gt;.2&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;El tipo "char" implica un valor de un solo caracter; mientras que "i32" implica un entero sin signo de 32 bits.&lt;/p&gt;

&lt;p&gt;Estaba claro que Rust era un lenguaje de bajo nivel que tenía características que comparten otros lenguajes más contemporaneos. Esto me resultaba preocupante, dado que no manejaba este nivel de complejidad.&lt;/p&gt;

&lt;p&gt;Por otro lado, &lt;strong&gt;Rust no maneja el paradigma orientado a objetos&lt;/strong&gt;. Esto me dejó un poco atontado, porque venía trabajando con esta forma en todos los lenguajes que me he cruzado. Aquí estamos frente al uso de los paradigmas imperativo y funcional. Si queremos algo similar a los objetos, necesitamos utilizar cosas como struct e impl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Brown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Brown&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"brown"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Red&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"red"&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;struct&lt;/span&gt; &lt;span class="n"&gt;Dimensions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Dimensions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"width: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.width&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"height: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"depth: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.depth&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;struct&lt;/span&gt; &lt;span class="n"&gt;ShippingBox&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dimensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dimensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ShippingBox&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dimensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dimensions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;dimensions&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;fn&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.color&lt;/span&gt;&lt;span class="nf"&gt;.print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.dimensions&lt;/span&gt;&lt;span class="nf"&gt;.print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"weight: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.weight&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;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;small_dimensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Dimensions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;small_box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ShippingBox&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;small_dimensions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;small_box&lt;/span&gt;&lt;span class="nf"&gt;.print&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;En este ejemplo, &lt;em&gt;ShippingBox&lt;/em&gt; es una estructura de datos que posee su propia implementación, así como también pasa con &lt;em&gt;Color&lt;/em&gt;. Es probable que los que estén más familiarizados con C, encuentren esto muy razonable; pero yo me crié (laboralmente) con lenguajes que aplicaban la POO, conjunto de sus patrones de diseño y buenas prácticas.&lt;/p&gt;

&lt;h1&gt;
  
  
  Finalmente descubrí donde estaba el amor.
&lt;/h1&gt;

&lt;p&gt;Si bien mi subtítulo es aplicable al título de una novela rosa, o un relato de Wattpad; la realidad es que finalmente encontré la clave de tanto amor a Rust: El concepto de Borrow, o "prestar".&lt;/p&gt;

&lt;p&gt;A diferencia de C/C++, donde teníamos que manejar la memoria a mano, Rust nos ofrece un sistema inteligente de préstamo de recursos. Por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"thirty"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Number of elements: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="nf"&gt;.len&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;Aquí podemos ver cómo recorro un vector de números mediante un bucle for. En un lenguaje tradicional, pedir el número de elementos luego de recorrerlo no sería un problema; pero en nuestro caso va a fallar en la compilación.&lt;/p&gt;

&lt;p&gt;Esto es porque la variable &lt;em&gt;nums&lt;/em&gt;, luego de ser procesada en un bucle (o pasada por una función), se destruye. Por supuesto, en este caso deberíamos evitarlo, y lo hacemos mediante el símbolo "&amp;amp;":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con este pequeño cambio, estamos pidiéndole a la función main (actual dueño de nuestro vector nums) que &lt;strong&gt;preste&lt;/strong&gt; al bucle &lt;em&gt;for&lt;/em&gt; dicho vector. Ésta técnica podría compararse con un pasaje de datos por referencia.&lt;/p&gt;

&lt;p&gt;Cuando nuestro bucle termina de utilizar su vector, lo devuelve a main() y se continúa su ejecución. Con este sistema de borrowing, podemos liberar memoria cuando realmente no necesitemos los recursos. Esto claramente es un digno competidor de los punteros en C; y supera con creces el Garbage Collector de lenguajes como Python, Java, C#, entre otros.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Éste&lt;/strong&gt; es el verdadero potencial de Rust. Y no, no somos dignos de esta maravillosa tecnología.&lt;/p&gt;

&lt;h1&gt;
  
  
  El trayecto final: La implementación.
&lt;/h1&gt;

&lt;p&gt;Con el fin de aplicar todo lo que aprendí, me propuse armar un proyecto sencillo y que ya esta publicado en GitHub: &lt;a href="https://github.com/maxwellnewage/rust-hero-game"&gt;Rust Hero Game&lt;/a&gt;. Este proyecto utiliza Rust para acceder a la API de &lt;a href="https://github.com/maxwellnewage/udemy-django-hero-game"&gt;Hero Game&lt;/a&gt; desarrollada en Django y DRF.&lt;/p&gt;

&lt;p&gt;En primer lugar, definí los recursos que iba a utilizar: tenía una API, y el endpoint más sencillo era "/api/players/", un GET que obtenía los jugadores sin pedir autenticación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"maxwell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"money"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"is_author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Encendí el servidor y me puse a trabajar en un archivo llamado api.rs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://127.0.0.1:8001/api/"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;make_api_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&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;let&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;reqwest&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
        &lt;span class="py"&gt;.json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Value&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;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&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;Definí una constante BASE_URL, la cual se explica por sí misma, y armé un método &lt;em&gt;make_api_request&lt;/em&gt;, el cual toma un endpoint y devuelve un enum Result que se lleva serde_json::Value (si la cosa fue bien) y Error (si salió algo mal).&lt;/p&gt;

&lt;p&gt;Utiliza async y await para detener los procesos en cada paso, pero seguir trabajando en los eventos asincrónicos como el llamado a la API y la conversión a json.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_all_players&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Player&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ApiError&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;let&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"players/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;make_api_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;from_value&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Player&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nf"&gt;Err&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ApiError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&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="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;Err&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ApiError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego, mi función &lt;em&gt;get_all_players&lt;/em&gt; llama a &lt;em&gt;make_api_request&lt;/em&gt;, pero procesa la respuesta para serializar el json en un struct Player:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Player&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;hp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&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="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;money&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Owner&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta manera, en main podemos trabajar con cada atributo como si fuera un "objeto":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nn"&gt;api&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get_all_players&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;players&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jugador: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;player&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="nf"&gt;Err&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error al obtener los jugadores: {}"&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="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;Dentro de cada player del for (devuelve un array de players en json, vector en Rust) podríamos acceder a propiedades como el dinero mediante &lt;em&gt;player.money&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Si corremos por consola el programa, obtendremos un resultado similar a este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Finished dev [unoptimized + debuginfo] target(s) in 0.82s
Running `target\debug\hero-game.exe`

Jugador: Player { hp: 50, id: 1, money: 99, name: "maxwell", score: 5, owner: Owner { id: 1, is_author: true, username: "admin" } }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusiones
&lt;/h1&gt;

&lt;p&gt;Creo que Rust es un excelente lenguaje de programación, creado bajo una muy buena idea acerca de cómo manejar los recursos en memoria. Al mismo tiempo, admito que no tengo las capacidades suficientes para dominarlo: puedo llevar un proyecto a cabo, pero he notado un grado de complejidad que me sobrepasa.&lt;/p&gt;

&lt;p&gt;Actualmente, no logro comprender en detalle los errores que lanza, y casi todo el tiempo me encuentro preguntándole a ChatGPT qué estoy haciendo.&lt;/p&gt;

&lt;p&gt;No obstante, esto también me sirve como una lección de humildad: todos los lenguajes que venía estudiando, los dominaba al mes. Hoy me cruzo con un gigante, y entiendo que parte de aprender se basa en la idea de admitir que no sabíamos todo; y que a veces hay que volver hacia atrás para tomar un envión más fuerte.&lt;/p&gt;

&lt;p&gt;Quiero aclarar que no tengo quejas con Rust, sino más bien observaciones comparables a mis otros aprendizajes. Y por supuesto, entrará en el stack que implica hacer este juego.&lt;/p&gt;

&lt;p&gt;En el próximo artículo, les contaré en detalle, a nivel mucho más técnico, sobre el clicker que me impulsó a aplicar Tauri y React.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>spanish</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Creo que me convertí en un desarrollador en React y Typescript</title>
      <dc:creator>Maximiliano Burgos</dc:creator>
      <pubDate>Tue, 16 May 2023 15:51:41 +0000</pubDate>
      <link>https://dev.to/maxwellnewage/creo-que-me-converti-en-un-desarrollador-en-react-y-typescript-2fkf</link>
      <guid>https://dev.to/maxwellnewage/creo-que-me-converti-en-un-desarrollador-en-react-y-typescript-2fkf</guid>
      <description>&lt;p&gt;Entiendo que el título puede sonar extraño, y claramente lo es: no era mi intención 🤣. Acompañame a este viaje que inició hace casi un mes, fruto de las necesidades de mis proyectos personales.&lt;/p&gt;

&lt;h2&gt;
  
  
  Desarrollar juegos será divertido, decían. La vas a pasar muy bien, decían.
&lt;/h2&gt;

&lt;p&gt;Siempre estoy desarrollando un juego en mis tiempos libres, sea por incluirlo en una de mis clases o simplemente porque así le saco todo el potencial a la herramienta que estoy utilizando.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://es.wikipedia.org/wiki/Stardew_Valley"&gt;Eric Barone&lt;/a&gt; quería aprender C# y como excusa creó Stardew Valley. A mi me pasa lo mismo con cada lenguaje o tecnología con la que me enfrento: desarrollar un juego es el equivalente a dispararte el pie. Tres veces.&lt;/p&gt;

&lt;p&gt;No se desesperen queridos/as lectores, en unos minutos me voy a poner serio. O no.&lt;/p&gt;

&lt;p&gt;La cuestión es que aprendí muchísimo mediante esta técnica, y la sigo aplicando con éxito. El problema es que me lo tomé en serio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maldito Cookie Clicker
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WdIB2E9P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elnykfjjrpxeaskaagi9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WdIB2E9P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elnykfjjrpxeaskaagi9.png" alt="Cookie Clicker" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto no es una imagen que encontré por ahí: es mi partida actual, en el momento en el que estoy escribiendo este artículo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://orteil.dashnet.org/cookieclicker/"&gt;Cookie Clicker&lt;/a&gt; es y será el mejor clicker incremental de la historia, sin discusión. Es un clásico que sigue en desarrollo continuo por nueve años.&lt;/p&gt;

&lt;p&gt;Y también es un tipo de droga que no fue registrada porque nadie quiere admitir que no hay tratamiento alguno. Este es el resultado de unas 287 horas y contando. Por supuesto, la mayoría son en segundo plano, mientras hago mis cosas.&lt;/p&gt;

&lt;p&gt;La cuestión es que decidí meterme en el género y crear mis propios clickers. La idea es innovar en una industria que no para de sacar ideas nuevas cada segundo, por lo cual va a ser un desafío interesante. Pero hablemos de la parte técnica.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clon de Cookie Clicker
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fukine3a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0uunz614kx7tx83jdwq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fukine3a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0uunz614kx7tx83jdwq.png" alt="Cookie Clicker Bender Meme" width="340" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Antes de meterme en un proyecto gigante, quería ahorrarme las frustraciones y crear un MVP de un juego ya creado, el cual tenía algunas de las mecánicas principales que iba a implementar en mis propios proyectos.&lt;/p&gt;

&lt;p&gt;Este es el resultado final! 💩&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0-kkUsoD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tgur69l61fouoee2sjq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0-kkUsoD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tgur69l61fouoee2sjq5.png" alt="Mi cookie Clicker" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En mi cabeza sonaba mejor. Aún así, lo considero un proyecto bañado en oro, por eso del famoso &lt;a href="https://es.wikipedia.org/wiki/Efecto_IKEA"&gt;efecto IKEA&lt;/a&gt;. Lo hice con amor, sudor y sangre.&lt;/p&gt;

&lt;p&gt;También lo hice para ustedes, hermosa comunidad, y lo pueden clonar desde &lt;a href="https://github.com/maxwellnewage/react-clicker"&gt;mi repositorio en GitHub&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Los motivos
&lt;/h2&gt;

&lt;p&gt;Cuando nos juntamos con &lt;a href="https://www.linkedin.com/in/francisco-toro-a3490816b/"&gt;Fran&lt;/a&gt; para empezar a darle forma al primer proyecto que vamos a desarrollar, sorteamos varios engines como Unity y PyGame.&lt;/p&gt;

&lt;p&gt;Pero nos encontramos con un problema fundamental: en ambos no teníamos tanta libertad para manejar el aspecto visual en un layout. En el caso de PyGame, los layouts en si no existen, es puro código y hay que acomodar cosas por axis. En el de Unity, tienen su propio sistema y una gestión un poco extraña de la UI. Además de que es un engine enorme para el tipo de juego que queríamos armar.&lt;/p&gt;

&lt;p&gt;También Godot fue un motivo de conversación, pero Fran lo detesta por alguna razón que todavía no descubro. Aún así, en este engine existe un metalenguaje llamado GDScript, el cual es similar a Python; y no me convencía tampoco.&lt;/p&gt;

&lt;p&gt;También probamos Tkinter y PyQT. El problema eran las animaciones, las cuales no ibamos a poder manejar como queríamos, conjunto de la optimización.&lt;/p&gt;

&lt;p&gt;La presencia de Python en nuestro stack era importante porque lo tomamos como el lenguaje core del juego. En este punto, decidimos que Django funcionaría como un administrador y generador de un dataset en SQLite, el cual contendría una serie de tablas que vendrían a definir gran parte de las reglas de nuestro clicker.&lt;/p&gt;

&lt;p&gt;Pero la parte frontend seguía siendo un tema complicado: hasta que se me ocurrió apuntar a web.&lt;/p&gt;

&lt;h2&gt;
  
  
  React fue mi primer opción
&lt;/h2&gt;

&lt;p&gt;Antes que nada, quiero aclarar que jamás toqué React y tengo un gran rechazo a Javascript. Aún así, no estoy ciego, y veo como el mercado pide más desarrolladores React de los que pueden nacer en el mundo.&lt;/p&gt;

&lt;p&gt;Además el paradigma reactivo y los videojuegos se llevan muy bien, dado que estos son un gran conjunto de eventos que interaccionan entre sí todo el tiempo.&lt;/p&gt;

&lt;p&gt;Por otro lado, yo empecé desarrollando web, por lo cual tenía un roadmap mental de la dirección que debíamos tomar.&lt;/p&gt;

&lt;h2&gt;
  
  
  El plan
&lt;/h2&gt;

&lt;p&gt;Antes de iniciar un proyecto, hay que armar un plan para entender los alcances y los pasos necesarios para progresar sin encontrar sorpresas muy grandes en el camino. Este era el plan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aprender Javascript (Fran)&lt;/li&gt;
&lt;li&gt;Comprender React a fondo&lt;/li&gt;
&lt;li&gt;Usar Electron para generar un ejecutable&lt;/li&gt;
&lt;li&gt;Crear una cuenta de desarrollador en Steam&lt;/li&gt;
&lt;li&gt;Publicar en Steam&lt;/li&gt;
&lt;li&gt;Mantener este juego por unos 8 años&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Con las bases del plan definidas, empezamos el viaje.&lt;/p&gt;

&lt;h2&gt;
  
  
  Etapa de aprendizaje y adopción
&lt;/h2&gt;

&lt;p&gt;Voy a contar mi camino, y quizá en el futuro, Fran escriba un artículo sobre el suyo.&lt;/p&gt;

&lt;p&gt;Como ya sabía Javascript, salté directamente a la librería de React. Miré muchos videos en YouTube, pero considero que aprendí mucho más con este:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/rLoWMU4L_qE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Pude entender parte de su potencial; y armé algunos proyectos simples para asentar las bases. Luego investigué sobre Electron y empezaron los problemas.&lt;/p&gt;

&lt;p&gt;Electron es la librería que permite generar un ejecutable en base a un proyecto web. El problema es que soporta una versión más antigua que no tiene este tipo de facilidades:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;algo&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./un_archivo.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entendí que la clave era cambiar las importaciones. Intenté hacerlo, pero el error persistía. Por supuesto, mucha gente había pasado por esto, y brindaban varias soluciones utilizando templates.&lt;/p&gt;

&lt;p&gt;Decidí probar uno, pero me di cuenta que estaban en TypeScript. No conocía este lenguaje, así que tuvimos que agregarlo a nuestro plan y buscar cursos.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gieEQFIfgYc"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;Me vi estas 8 horas de video en dos o tres días, y luego empecé a practicar en el editor Visual Studio Code. Al principio no me sentí muy cómodo con este lenguaje de programación (que en realidad es un superset de Javascript), pero luego de utilizarlo en un proyecto con React, me empezó a gustar.&lt;/p&gt;

&lt;p&gt;Su fuerte tipado evita los desastres que se podían cometer en Javascript; al mismo tiempo ayuda al editor a entender cuáles son los atributos de un determinado tipo y también a advertir errores si estamos pasando valores erróneos.&lt;/p&gt;

&lt;p&gt;Luego de la comprensión, llegó la unión de conceptos, y pude crear un proyecto con un template de Electron, Vite, TypeScript y React. Fue un Hello World, pero estaba feliz porque todo se había encastrado y funcionaba perfecto.&lt;/p&gt;

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

&lt;p&gt;Considero que este artículo me está quedando gigante, y voy a dejar el desarrollo en detalle del clon de Cookie Clicker para una segunda parte. No obstante, espero que les haya podido trasmitir mi experiencia en el camino del desarrollo y puedan tomarlo de ejemplo para sus emprendimientos.&lt;/p&gt;

&lt;p&gt;Si les gustó, compartan, y déjenme un comentario, los leo!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>spanish</category>
      <category>typescript</category>
      <category>react</category>
    </item>
  </channel>
</rss>
