<?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: Marcelo Andrade R.</title>
    <description>The latest articles on DEV Community by Marcelo Andrade R. (@marceloandrade).</description>
    <link>https://dev.to/marceloandrade</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%2F18574%2F78af56f8-28b0-4e43-b1c0-7c73462fd2ca.jpg</url>
      <title>DEV Community: Marcelo Andrade R.</title>
      <link>https://dev.to/marceloandrade</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marceloandrade"/>
    <language>en</language>
    <item>
      <title>Como trabajo</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Tue, 14 Jun 2022 17:16:35 +0000</pubDate>
      <link>https://dev.to/marceloandrade/como-trabajo-3bf</link>
      <guid>https://dev.to/marceloandrade/como-trabajo-3bf</guid>
      <description>&lt;p&gt;He trabajado de forma remota por casi 9 años y al principio como en todo cambio traté de hacer las cosas de la misma manera que se hace en presencial, tener un horario de 9 a 18, asistir a reuniones, pedir permiso para salir del trabajo, etc. etc. Pero luego de este tiempo he cambiado muchas cosas y vale la pena compartir la forma en la que trabajo en la actualidad.&lt;/p&gt;

&lt;p&gt;Me pareció interesante un documento que encontré en la web de &lt;a href="https://t%C3%B5m.com/ceo-of-human-made-how-i-work/"&gt;Tom Willmot - CEO de Human Made&lt;/a&gt; así que voy a hacer un fork de este documento y adaptarlo a mi realidad.&lt;/p&gt;

&lt;h2&gt;
  
  
  Descripción de mi rol
&lt;/h2&gt;

&lt;p&gt;Trabajo como Ingeniero de Software / Consultor de Tecnología para algunos clientes nacionales e internacionales.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mis responsabilidades
&lt;/h2&gt;

&lt;p&gt;Dependiendo del cliente con el que tengo un contrato activo tengo diferentes responsabilidades, entre las que están:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Diseñar y crear software de calidad para el manejo de los procesos de negocio de mis clientes&lt;/li&gt;
&lt;li&gt;Mantener los servicios funcionando para que no haya interrupciones en el trabajo de los usuarios de los sistemas&lt;/li&gt;
&lt;li&gt;Estar al día en actualizaciones de los sistemas para evitar incidentes de seguridad&lt;/li&gt;
&lt;li&gt;Dar soporte de las aplicaciones que soy responsable&lt;/li&gt;
&lt;li&gt;Dar mi opinión acerca de consultas de parte de mis clientes en el área de tecnología&lt;/li&gt;
&lt;li&gt;Presupestar nuevos desarrollos&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Como trabajo
&lt;/h2&gt;

&lt;p&gt;Este es un documento vivo en el que indico mi forma de trabajar, si has trabajado conmigo y este documento no refleja tu experiencia dejame saber para actualizarlo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cuando trabajo
&lt;/h3&gt;

&lt;p&gt;Usualmente trabajo de Lunes a Viernes y casi nunca en fin de semana. Hago 2 o máximo 3 secciones en los días de trabajo, la primera sección es de 6:30 a 8:00 y la segunda sección de 9:00 a 13:00, hay veces que tengo trabajo extra o estoy en medio de un proyecto con fecha límite, ahí uso la tercera sección de 21h00 a 22h30.&lt;/p&gt;

&lt;p&gt;Todos las horas son UTC-5 hora Ecuador continental. Los tiempos intermedios son para asuntos personales y familiares y generalmente no contesto durante estos períodos.&lt;/p&gt;

&lt;p&gt;Es posible que ciertos días tenga que tomar citas médicas o cosas que no puedo aplazar en las secciones de trabajo. Haré saber a las personas con las que estoy trabajando directamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Donde trabajo
&lt;/h3&gt;

&lt;p&gt;Desde un oficina en casa compartida con mi esposa e hijas, vivo en Quito, Ecuador.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como trabajo
&lt;/h3&gt;

&lt;p&gt;Mi día a día es generalmente 1 o 2 reuniones planificadas máximo a la semana, y el resto del tiempo lo dedico al desarrollo de software, operación de los servicios y al aprendizaje de nuevas tecnologías.&lt;/p&gt;

&lt;p&gt;Lo más importante para mí es &lt;strong&gt;entender&lt;/strong&gt; la necesidad del cliente para realizar un nuevo requerimiento o cambio en los procesos para poder entregar la mejor solución posible en el menor tiempo.&lt;/p&gt;

&lt;p&gt;Las tareas pendientes que tengo en su mayoría tienen un lugar para vivir, si son cambios o requerimientos dependiendo del cliente pueden vivir en jira o trello. Y las consultas y soporte en la bandeja de entrada de mi correo electrónico. Trato de tener un &lt;a href="https://blog.superhuman.com/inbox-zero-method/"&gt;Inbox Zero&lt;/a&gt; así que todo lo que está en mi inbox necesita mi atención.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comunicaciones
&lt;/h3&gt;

&lt;p&gt;Trato de comunicarme de la mejor manera, pongo especial énfasis en la comunicación escrita, ya que al trabajar remoto, la mejor manera de compartir información es de forma asíncrona y escrita.&lt;/p&gt;

&lt;p&gt;Mis canales de comunicación instantánea están siempre abiertos. Con los clientes internacionales casi siempre es Google Chat o Slack, y para los nacionales WhatsApp.&lt;/p&gt;

&lt;p&gt;En mi teléfono no tengo notificaciones audibles, así que solo veré las notificaciones cuando tome el teléfono. Cuando estoy frente a mi laptop si tengo las notificaciones activadas.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Siempre prefiero un email a una reunión.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Si yo inicio la comunicación escrita no espero una respuesta inmediata a menos que lo indique, pueden responder cuando estén listos, pero voy a recordarles de responder en un tiempo prudencial si no he tenido una respuesta.&lt;/p&gt;

&lt;p&gt;Prefiero comunicación escrita por las siguientes razones: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Porque tengo registro de los intercambios&lt;/li&gt;
&lt;li&gt;Puedo reflexionar y pensar mejor mis respuestas. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Solo si la conversación no está llevando a nada haremos una reunión virtual y aclararemos las cosas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cancelar reuniones o llamadas
&lt;/h3&gt;

&lt;p&gt;Trato de no cancelar de último momento a menos que sea una emergencia y espero lo mismo de los demás.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redes Sociales
&lt;/h3&gt;

&lt;p&gt;Tengo cuentas en la mayoría de sitios, pero no publico mucho. Facebook para mis redes personales. &lt;a href="https://twitter.com/MarceloAndrade"&gt;Twitter&lt;/a&gt; y &lt;a href="https://www.linkedin.com/in/marceloandrader/"&gt;LinkedIn&lt;/a&gt; para profesionales.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cosas que amo
&lt;/h3&gt;

&lt;p&gt;Amo a mi familia, la principal razón para seguir adelante. &lt;/p&gt;

&lt;p&gt;Me gusta solucionar problemas. Aprender de diferentes industrias y tecnologías. Conocer gente interesante. Salir a caminar en el campo. Leer. Escribir cada semana. Ver buenas series.&lt;/p&gt;

</description>
      <category>remotework</category>
    </item>
    <item>
      <title>Newsletter #53</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Thu, 09 Jun 2022 16:24:32 +0000</pubDate>
      <link>https://dev.to/marceloandrade/newsletter-53-15gi</link>
      <guid>https://dev.to/marceloandrade/newsletter-53-15gi</guid>
      <description>&lt;p&gt;Hey, I've been writing weekly for a while, if you'd like to subscribe to my newsletter, it's in spanish but I can start writing in English soon depending on demand:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marceloandrader.ck.page/posts"&gt;ConvertKit Public Page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last publication:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marceloandrader.ck.page/posts/devtools-design-systems-y-mas"&gt;🎨 DevTools, Design Systems y más&lt;/a&gt;&lt;/p&gt;

</description>
      <category>newsletter</category>
    </item>
    <item>
      <title>Creating a shark with a serverless function</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Tue, 07 Jun 2022 17:43:38 +0000</pubDate>
      <link>https://dev.to/marceloandrade/creating-a-shark-with-a-serverless-function-40a</link>
      <guid>https://dev.to/marceloandrade/creating-a-shark-with-a-serverless-function-40a</guid>
      <description>&lt;p&gt;There is a new &lt;a href="https://dev.to/digitalocean/digitalocean-functions-challenge-1f2c"&gt;challenge from Digital Ocean&lt;/a&gt;, it was easy to complete, I choose to create the function from the control panel and was super easy to setup with PHP and just calling the API with curl.&lt;/p&gt;

&lt;p&gt;You can see my robot shark called Marcelo in the &lt;a href="https://functionschallenge.digitalocean.com/"&gt;aquarium&lt;/a&gt; &lt;/p&gt;

</description>
      <category>digitalocean</category>
      <category>serverless</category>
      <category>functions</category>
    </item>
    <item>
      <title>Generando datos de prueba rapidamente</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Thu, 17 Mar 2022 16:45:00 +0000</pubDate>
      <link>https://dev.to/marceloandrade/generando-datos-de-prueba-rapidamente-3kfj</link>
      <guid>https://dev.to/marceloandrade/generando-datos-de-prueba-rapidamente-3kfj</guid>
      <description>&lt;p&gt;Durante las pruebas manuales, muchas veces se necesita ingresar datos de prueba en los formularios de los sistemas en los que trabajo. La carga mental de estar programando y probando generalmente afecta el pensar nuevos datos randómicos para datos de pruebas, y lo más fácil es usar datos ya predefinidos como "asdf", "qwerty", "test1", "test2", pero encontré una manera más fácil de generar estos datos.&lt;/p&gt;

&lt;p&gt;La práctica que me ha ayudado a agilizar esta parte del  proceso de prueba manual es usar 2 herramientas, la una es un &lt;strong&gt;expansor de texto&lt;/strong&gt;, la idea de este tipo de herramientas es minimizar el tipeado de información al usar shortcuts cuando se escribe algo, por ejemplo, si en tus emails siempre saludas o te despides con el mismo texto, puedes configurar al expansor para que al ingresar &lt;code&gt;:saludo&lt;/code&gt; se auto expanda a &lt;code&gt;Hola, Te saluda Marcelo&lt;/code&gt; ahorrandote tiempo y energía. Para esta parte uso &lt;a href="https://espanso.org/"&gt;espanso&lt;/a&gt; es multiplataforma y muy fácil de instalar y configurar.&lt;/p&gt;

&lt;p&gt;Para la segunda parte uso un &lt;strong&gt;generador de datos falsos&lt;/strong&gt; &lt;a href="https://fakerphp.github.io/"&gt;faker&lt;/a&gt; es una librería de PHP que permite generar datos de prueba, hay librerías simlares para otros lenguajes, pero esta me queda bien porque puedo instalarla como librería global con composer usando &lt;code&gt;composer global require fakerphp/faker&lt;/code&gt; luego puedo usar directamente en la línea de comandos con: &lt;code&gt;php -r "require_once '/home/marcelo/.config/composer/vendor/autoload.php'; echo Faker\\Factory::create()-&amp;gt;firstName();"&lt;/code&gt; cada vez que ejecuto este comando me da un nuevo primer nombre.&lt;/p&gt;

&lt;p&gt;Ahora al unir ambas tengo este tipo de definición en la configuración de espanso:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WKx8o7aw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ro8os9f6brrfwlrqdqsb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WKx8o7aw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ro8os9f6brrfwlrqdqsb.png" alt="Image description" width="880" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cada vez que digito &lt;code&gt;:fn&lt;/code&gt; en cualquier aplicación, se autoexpande a un nombre aleatorio, lo mismo con &lt;code&gt;:ln&lt;/code&gt; en cualquier aplicación, se autoexpande a un apellido aleatorio, y de igual manera para &lt;code&gt;:city&lt;/code&gt;, &lt;code&gt;:state&lt;/code&gt;, &lt;code&gt;:address&lt;/code&gt;, &lt;code&gt;:zip&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Revisando la documentación de faker puedes agregar aún más shortcuts a espanso.&lt;/p&gt;

</description>
      <category>tip</category>
      <category>testing</category>
      <category>php</category>
    </item>
    <item>
      <title>Pub/Sub con Redis</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Mon, 07 Mar 2022 12:27:53 +0000</pubDate>
      <link>https://dev.to/marceloandrade/pubsub-con-redis-10ap</link>
      <guid>https://dev.to/marceloandrade/pubsub-con-redis-10ap</guid>
      <description>&lt;p&gt;Durante esta semana tuve que hacer refactoring de una parte del sistema en el que trabajo tenemos un portal de cliente en el que los usuarios pueden seleccionar reportes a descargar y se genera un pdf o un zip con toda la información equerida.&lt;/p&gt;

&lt;p&gt;El problema era que estos reportes pueden llegar a ser bastante grandes y estaban dando timeouts al generarlos online durante el request HTTP, dejando a los usuarios en espera con una pantalla en blanco sin saber cual fue el error cuando falla.&lt;/p&gt;

&lt;p&gt;Hicimos algunas optimizaciones para generar el reporte más  rápido pero aún así  podía demorar algunos minutos, queríamos hacer algo que no le deje al usuario sin feedback, ya teníamos la opción de poner la generación de este reporte en una cola para que sea consumida por unos procesos en background, pero el usuario no sabía que estaba haciendo el sistema durante su espera hasta recibir el email de que el reporte ha finalizado.&lt;/p&gt;

&lt;p&gt;Así que decidimos siempre generar los reportes en background, pero dándole al usuario un monitoreo del proceso mientras se genera. Para esto investigue las opciones existentes para mostrar mensajes generados durante el proceso de creación del reporte. La opción que mejor se acoplaba era enviar mensajes desde el servidor web usando &lt;a href="https://jvns.ca/blog/2021/01/12/day-36--server-sent-events-are-cool--and-a-fun-bug/"&gt;SSE (Server Sent Events)&lt;/a&gt; de tal forma que no se necesite hacer demasiados requests haciendo polling, pero hubo que hacer algunas configuraciones en nginx para no hacer buffering de la respuesta de la aplicación pero una vez hecho eso, desde el front end se crea un EventSource y en cada mensaje se muestra información en pantalla. Primera parte resuelta, pero ya que el proceso que está generando el reporte no tiene forma de comunicarse con el servidor&lt;br&gt;
para mostrar el porcentaje de avance se necesita un middleman para emparejar ambos, es aquí donde necesitaba un sistema PUB/SUB (Publisher/subscriber). Si hubiera estado usando postgres esto ya lo tiene resuelto, usando LISTEN and NOTIFY. Pero como usamos mariadb en este proyecto  hubo que agregar un nuevo componente al sistema.&lt;/p&gt;

&lt;p&gt;El componente fue redis, sabía de este pero no lo había usado antes, es un almacenamiento en memoria de diferentes estructuras de datos, se puede usar como base de datos, cache o broker de mensajes.&lt;/p&gt;

&lt;p&gt;La característica que estamos usando en este momento se llama &lt;a href="https://redis.io/topics/pubsub"&gt; Pub/Sub &lt;/a&gt;, y lo que permite es publicar mensajes a un canal específico y otros procesos pueden suscribirse a escuchar mensajes de un canal o canales que le interesa.&lt;/p&gt;

&lt;p&gt;Para implementarlo simplemente agregue redis como dependencia en mi docker-compose.yml e instale el paquete php-redis para poder tener las clases que me permitan conectarme al servidor de redis, una vez hecho eso el código es bastante simple, en la clase que maneja los procesos de background simplemente se hace un &lt;code&gt;$redis-&amp;gt;publish('job_1', "Iniciando reporte");&lt;/code&gt; y en el controller que maneja los SSE se hace un &lt;code&gt;$redis-&amp;gt;listen(['job_1'], fn ...);&lt;/code&gt; donde fn es el callback que se llama  cada vez que se envía un nuevo mensaje al canal denominado job_1, este nombre de canal es dinámico.&lt;/p&gt;

&lt;p&gt;Este sistema ha estado trabajando muy bien desde la puesta a producción, el consumo de memoria de redis tampoco es elevado, le puse 1GB de RAM pero solo consume 3 MB.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>¿Por qué? la mágica pregunta al desarrollar software</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Wed, 16 Feb 2022 12:43:46 +0000</pubDate>
      <link>https://dev.to/marceloandrade/por-que-la-magica-pregunta-al-desarrollar-software-1gal</link>
      <guid>https://dev.to/marceloandrade/por-que-la-magica-pregunta-al-desarrollar-software-1gal</guid>
      <description>&lt;p&gt;Cuando el negocio nos solicita un requerimiento, generalmente&lt;br&gt;
como técnicos tendemos a empezar la solución de este&lt;br&gt;
lo antes posible, tal vez preguntemos acerca de&lt;br&gt;
quienes lo van a usar, que información necesitamos&lt;br&gt;
guardar para luego usar en reportes, los permisos que deberá&lt;br&gt;
tener, y empezamos a validar en nuestra mente la mejor manera&lt;br&gt;
de desarrollarlo en el sistema, pero una pregunta importante que muchas veces&lt;br&gt;
no hacemos y que deberíamos hacer frecuentemente es:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Por qué?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;¿Por qué se necesita aumentar un campo a un formulario?&lt;/li&gt;
&lt;li&gt;¿Por qué es necesario ejecutar un reporte cada cierto tiempo?&lt;/li&gt;
&lt;li&gt;¿Por qué mover un botón a otra parte de la pantalla?&lt;/li&gt;
&lt;li&gt;¿Por qué enviar un nuevo correo electrónico al cliente luego de una acción?&lt;/li&gt;
&lt;li&gt;¿Por qué debemos capturar el tráfico de un sitio web?&lt;/li&gt;
&lt;li&gt;¿Por qué &lt;em&gt;Inserte aquí el requerimiento&lt;/em&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esto nos permite tener una perspectiva diferente, poder conocer&lt;br&gt;
las razones del &lt;strong&gt;negocio&lt;/strong&gt; para solicitarlo, nos ayuda&lt;br&gt;
a entender de mejor manera los &lt;strong&gt;objetivos&lt;/strong&gt; que se quieren lograr&lt;br&gt;
con el requerimiento, el poder no solo pensar desde el punto de &lt;br&gt;
vista técnico sino como parte de la empresa.&lt;/p&gt;

&lt;p&gt;Al principio es posible que no obtengamos la respuesta que&lt;br&gt;
queremos, es posible que nos den una respuesta vaga como: &lt;br&gt;
&lt;strong&gt;mejorar la experiencia de usuario&lt;/strong&gt;, pero no debemos quedarnos ahí&lt;br&gt;
debemos usar la técnica de &lt;a href="https://es.wikipedia.org/wiki/Los_cinco_%C2%BFPor_qu%C3%A9%3F"&gt; los 5 ¿Por qué? &lt;/a&gt;&lt;br&gt;
debemos encontrar la raíz del requerimiento, para así tener&lt;br&gt;
la mejor forma de medir si un requerimiento va a cumplir o no &lt;br&gt;
el objetivo del negocio.&lt;/p&gt;

&lt;p&gt;Muchas veces el lado del negocio solo piensa que como técnicos&lt;br&gt;
solo debemos dedicarnos a ese sector y no opinar acerca&lt;br&gt;
de posibles alternativas que pueden ayudar a conseguir&lt;br&gt;
el objetivo planteado. Y como técnicos no solo debemos &lt;br&gt;
entrenarnos en los últimos frameworks, o lenguajes o aplicaciones&lt;br&gt;
sino también y tal vez en mayor medida en aprender&lt;br&gt;
cómo funciona la empresa, cómo hace dinero, a quién servimos,&lt;br&gt;
qué esperan los clientes de la empresa, etc.  De tal forma&lt;br&gt;
que seamos los coadyuvantes del mejoramiento de la empresa&lt;br&gt;
en su totalidad no solo del departamento de tecnología de información.&lt;/p&gt;

&lt;p&gt;Una vez que conocemos los objetivos y también tenemos una&lt;br&gt;
mayor comprensión del negocio, podemos dar nuestra opinión&lt;br&gt;
acerca de las mejores opciones de solución, muchas veces la solución no &lt;br&gt;
es cambiar los sistemas, puede ser necesario cambiar&lt;br&gt;
procesos internos, o contratar software o servicios de terceros,&lt;br&gt;
o incluso dejar de hacer cosas que no contribuyen a fortalecer los objectivos&lt;br&gt;
de la empresa.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Aplicaciones web ambiciosas con Ember.js</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Thu, 24 Jun 2021 14:47:06 +0000</pubDate>
      <link>https://dev.to/marceloandrade/aplicaciones-web-ambiciosas-con-ember-js-4o7m</link>
      <guid>https://dev.to/marceloandrade/aplicaciones-web-ambiciosas-con-ember-js-4o7m</guid>
      <description>&lt;p&gt;Cuando se trata de crear aplicaciones de página única o SPA en inglés,&lt;br&gt;
como desarrolladores tenemos muchas opciones de dónde escoger &lt;br&gt;
hay frameworks y librerías muy conocidas como angular en el área de framework&lt;br&gt;
y vue | react en el área de librería.&lt;/p&gt;

&lt;p&gt;Hoy quiero hablarles de un framework no muy usado o conocido&lt;br&gt;
pero que merece ser mencionado: &lt;a href="https://emberjs.com/"&gt;Ember.js&lt;/a&gt;. He trabajado&lt;br&gt;
con este framework por al menos 6 años, y la forma en la que llegué a este&lt;br&gt;
fue un poco graciosa, en ese tiempo estaba dando los tests para entrar&lt;br&gt;
a la comunidad de freelancers &lt;a href="https://www.toptal.com/NWaLA1/worlds-top-talent"&gt;Toptal&lt;/a&gt; uno &lt;br&gt;
de los pasos era realizar un pequeño proyecto y para esto escogí Ember.js y PHP en el backend&lt;br&gt;
lo escogí como para aprender, había trabajado en el pasado con knockout.js, angular js, &lt;br&gt;
backbone y por supuesto jQuery; pero quería algo que realmente ayudara en la productividad,&lt;br&gt;
luego de ser aceptado en Toptal, la primera entrevista con un cliente era&lt;br&gt;
para llenar un puesto para trabajar con Ember, en principio dude en aplicar&lt;br&gt;
porque solo lo había aprendido para hacer este test, pero el reclutador me&lt;br&gt;
animó y la entrevista fue muy bien y desde entonces estoy trabajando con este cliente&lt;br&gt;
con 4 aplicaciones internas grandes hechas en Ember.&lt;/p&gt;

&lt;p&gt;Una de los principios de Ember.js es que la evolución no debe ser drástica,&lt;br&gt;
como en el caso de angular que hubo un re-write del framework y los que crearon&lt;br&gt;
una app con angular js no pudieron pasar directamente a angular v2, la idea&lt;br&gt;
de Ember era siempre hacer las transiciones de versiones lo más seguras&lt;br&gt;
y fáciles posibles, para esto proveen con muchas herramientas, como &lt;code&gt;deprecations&lt;/code&gt;&lt;br&gt;
para que desde una versión anterior comiencen a notarse los cambios que se activarán&lt;br&gt;
en las versiones posteriores y que alertan a los desarrolladores para cambiar el código de la aplicación&lt;br&gt;
para una futura actualización sin novedades, también existen &lt;code&gt;codemods&lt;/code&gt;&lt;br&gt;
para que los cambios se hagan automáticamente, e incluso hay &lt;code&gt;feature flags&lt;/code&gt; que&lt;br&gt;
permiten probar características que saldrán públicas en futuras versiones&lt;br&gt;
en versiones anteriores.&lt;/p&gt;

&lt;p&gt;El framework ya lleva 10 años con una comunidad pequeña pero&lt;br&gt;
con gente de mucha calidad y muy abierta e inclusiva. En cuestión de paquetes disponibles&lt;br&gt;
para la comunidad hay una gran variedad, puedes chequear &lt;a href="https://emberobserver.com/"&gt;Ember Observer&lt;/a&gt;&lt;br&gt;
donde se registran todos los addons que tienen compatibilidad con Ember.&lt;/p&gt;

&lt;p&gt;Como ejemplos de aplicaciones públicas desarrolladass con Ember están LinkedIn, Heroku, Intercom, Square.&lt;/p&gt;

&lt;p&gt;En cuestiones un poco más técnicas, el framework tiene muchas opiniones en su diseño&lt;br&gt;
tal vez para muchos esto no es bueno, para mi es fantástico, no tienes que tomar decisiones&lt;br&gt;
de qué usar cada 5 minutos, porque como comunidad ya se hizo esta decisión a travez&lt;br&gt;
de procesos denominados RFC en github para realizar cambios. La estructura de las aplicaciones&lt;br&gt;
es estándar, si has trabajado en una app ember, puedes trabajar en otra muy rápidamente&lt;br&gt;
porque sabes dónde está y cómo funciona todo.&lt;/p&gt;

&lt;p&gt;La URL en aplicaciones ember es tratada como una parte fundamental, ya que de la misma se puede derivar&lt;br&gt;
el ruteo, estático y dinámico, y adicional parametros de consulta. Es el punto de entrada&lt;br&gt;
hacia las rutas de la aplicación que a su vez manejan el modelo de datos que es transferido hacia&lt;br&gt;
los templates que usan componentes para mostrar y manejar la interfaz al usuario.&lt;/p&gt;

&lt;p&gt;Se puede hacer Test Driven Development muy fácilmente con tests unitarios para cada componente o utilidad&lt;br&gt;
y tests e2e para ejecutar caminos complejos de interacciones de usuario.&lt;/p&gt;

&lt;p&gt;Si a alguien le interesa más detalles de cómo funciona el framework, suscríbanse y dejenme saber.&lt;/p&gt;

</description>
      <category>ember</category>
    </item>
    <item>
      <title>Debería aprender PHP o está de bajada?</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Thu, 17 Jun 2021 13:43:20 +0000</pubDate>
      <link>https://dev.to/marceloandrade/deberia-aprender-php-o-esta-de-bajada-1f05</link>
      <guid>https://dev.to/marceloandrade/deberia-aprender-php-o-esta-de-bajada-1f05</guid>
      <description>&lt;p&gt;He escuchado muchas veces la pregunta si debería o no un nuevo programador o ingeniero salido de la universidad aprender PHP. La respuesta como todo en la vida, &lt;strong&gt;depende&lt;/strong&gt;. Depende especialmente de hacia dónde quiera dirigir su carrera esta persona.&lt;/p&gt;

&lt;p&gt;En el ambiente empresarial siempre hay un sentimiento de desprecio hacia el lenguaje PHP, y un tinte de superioridad hacia lenguajes más usados en estas instituciones como java o C#. Es verdad que desde hace mucho tiempo hasta las versiones 4 o 5 de PHP, realmente PHP tenía muchas "características" que no lo hacían ver bien en el ambiente empresarial, hacía conversiones automáticas de tipos de datos, si sumabas cadenas y números "asumía" lo que querías hacer y simplemente convertía la cadena a número y luego sumaba, es un lenguaje dinámico, hasta cierto punto demasiado dinámico para muchos gustos. Pero este lenguaje ha ido evolucionando bastante, se tiene soporte muy extendido de programación Orientada a Objetos y también Funcional, pero no se puede negar que aún con estas nuevas características un mal programador aún puede crear programas "Frankensteins" en este, usando código procedural, mezclando html con php para generar páginas dinámicas, etc.&lt;/p&gt;

&lt;p&gt;Así que si la ídea es trabajar en empresas, PHP tal vez no sea la mejor recomendación para aprender.&lt;/p&gt;

&lt;p&gt;Tampoco podemos tapar el sol con un dedo y disminuir todo lo que es posible hacer con PHP. Con el &lt;a href="https://w3techs.com/technologies/overview/programming_language"&gt;79%&lt;/a&gt; del mercado de sitios web usando PHP, tampoco es que le va a faltar trabajo si se orienta la carrera hacia negocios en la web. Entre las grandes empresas de tecnología que usan PHP en alguna parte de su "stack" están Facebook, Slack, Wikipedia, entre otras. Muchos negocios pequeños también tienen su nido en la web a través de Wordpress, Drupal o Joomla que son CMS desarrollados en PHP.&lt;/p&gt;

&lt;p&gt;PHP tiene mucahs ventajas, entre ellas por ejemplo a la hora de desplegar sitios web o applicaciones web en Internet, la mayoría de las empresas de hosting hacen muy fácil poner una aplicación PHP en sus servidores a través de subir archivos via sFTP o SCP, no lo recomiendo pero así se empieza. También se puede usar con muchas bases de datos, en la web las preferidas son mysql y postgres, pero de ser necesario también se puede conectar con bases oracle o sql server. El flujo de trabajo en PHP es muy rápido, pienso, hago el cambio en el archivo y hago f5 en el browser y ya puedo ver el cambio.&lt;/p&gt;

&lt;p&gt;Ahora también hay muchos frameworks que van a evitar que te dispares en tu propio pie a la hora de hacer una aplicación PHP, mi recomendación es aprender el lenguaje tratar una aplicación pequeña en PHP puro (que no vaya a ponerse en producción) y luego aprender un framework de desarrollo PHP como &lt;a href="https://symfony.com/"&gt;symfony&lt;/a&gt; o &lt;a href="https://laravel.com/"&gt;laravel&lt;/a&gt; aparte de proveer mucha funcionalidad estos frameworks permiten mantener una aplicación ordenada y bien separada cada capa de programación.&lt;/p&gt;

&lt;p&gt;Otra recomendación es leer este sitio web &lt;a href="https://phptherightway.com/"&gt;PHP The Right Way&lt;/a&gt; por favor la versión en Inglés porque la de español está bastante desactualizada. Este informa bastante bien cómo trabajar con PHP de una forma sensata y ordenada para evitar sorpresas.&lt;/p&gt;

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

&lt;p&gt;Al final la decisión es propia y es cuestión de gustos. En mi caso al inicio de mi carrera luego de la universidad use PowerBuilder, java y tecnologías Microsoft, pero una vez que hice el cambio a PHP se abrieron muchas puertas, especialmente en el exterior por lo que si aprendes PHP recomendaría también aprender Inglés.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forms.gle/VNBQara7jQq8HdzcA"&gt;Gracias por llegar hasta aquí, ayúdame llenando esta encuesta, me gustaría saber en qué lenguaje trabajas&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>php</category>
    </item>
    <item>
      <title>Usando transacciones en bases de datos</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Thu, 27 May 2021 12:40:43 +0000</pubDate>
      <link>https://dev.to/marceloandrade/usando-transacciones-en-bases-de-datos-m5l</link>
      <guid>https://dev.to/marceloandrade/usando-transacciones-en-bases-de-datos-m5l</guid>
      <description>&lt;p&gt;Al escribir la lógica de una aplicación que interactúa con una base de datos relacional&lt;br&gt;
para almacenar la información, generalmente se puede tener varios&lt;br&gt;
pasos para guardar cada pedazo en un lugar específico de la base, las bases de datos denominadas&lt;br&gt;
&lt;a href="https://es.wikipedia.org/wiki/ACID"&gt;ACID&lt;/a&gt; tienen una herramienta poderoza para evitar inconsistencias de datos&lt;br&gt;
hoy nos concentraremos en la A de ACID Atomicidad.&lt;/p&gt;

&lt;p&gt;Por ejemplo cuando se crea una factura, no solo se guarda como un documento en la base,&lt;br&gt;
se tiene varias tablas como: &lt;code&gt;factura&lt;/code&gt;, &lt;code&gt;detalle_factura&lt;/code&gt;, &lt;code&gt;inventario&lt;/code&gt;, &lt;code&gt;producto&lt;/code&gt;, etc. Al enviar la información&lt;br&gt;
desde la interfaz de usuario hacia la aplicación podemos tener una sola estructura con todos los &lt;br&gt;
datos necesarios para crear la factura, pero a nivel de aplicación debemos analizar esa estructura&lt;br&gt;
y leerla para que cada parte se guarde en una tabla específica de la base de datos, de tal forma&lt;br&gt;
que tendremos un registro para &lt;code&gt;factura&lt;/code&gt; con los datos de la cabecera, varios registros de &lt;code&gt;detalle_factura&lt;/code&gt;&lt;br&gt;
y adicionalmente se debe modificar las cantidades de los productos en el detalle del &lt;code&gt;inventario&lt;/code&gt; de cada &lt;code&gt;producto&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si tomamos la vía rápida de hacerlo todo esperando que nada falle, tendremos código cómo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="c1"&gt;// ... solo el código que interesa para el ejemplo&lt;/span&gt;
&lt;span class="nv"&gt;$factura&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Factura&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$datosDeFactura&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$factura&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalleDeFactura&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$detalle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DetalleFactura&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;factura&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$factura&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;producto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Producto&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'producto_id'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$inventario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Inventario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$inventario&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;producto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Producto&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'producto_id'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$inventario&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&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;Como podemos ver estamos usando algún tipo de ORM en el que creamos los objetos con datos y guardamos cada uno,&lt;br&gt;
el problema sucede si digamos en la estructura de datos enviada, uno de los &lt;code&gt;producto_id&lt;/code&gt; no está en la tabla de productos.&lt;br&gt;
De tal forma que si enviamos una lista con 3 productos y el último id no está definido, en este código se creará&lt;br&gt;
una factura con 2 detalles y 2 afectaciones a inventario, en el último producto el sistema dará un fallo y no podrá &lt;br&gt;
seguir, pero en la base de datos ya se escribió parte de la información.&lt;/p&gt;

&lt;p&gt;Para solucionar este gran inconveniente debemos usar una herramienta que todas las bases de datos relacionales&lt;br&gt;
tienen, &lt;strong&gt;TRANSACCIONES&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A nivel de base de datos desde un cliente por ejemplo, es fácil comenzar una transacción con el comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego se puede hacer varias operaciones de lectura y/o escritura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="nv"&gt;`factura`&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fecha&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;estado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'001-001-1000'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2021-05-27'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Facturada'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="nv"&gt;`detalle_factura`&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="n"&gt;producto_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cantidad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;precio&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&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;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Al final se puede decidir si guardo todos los cambios o regreso al estado original antes de enviar el comando BEGIN. Si deseo escribir&lt;br&gt;
uso el comando &lt;strong&gt;COMMIT&lt;/strong&gt;, si quiero descartar todos los cambios uso el comando &lt;strong&gt;ROLLBACK&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;--- o &lt;/span&gt;
&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto nos asegura que en el COMMIT todas las operaciones realizadas se ejecutan como una sola operación o no se ejecuta nada, &lt;br&gt;
a esto se le llama &lt;strong&gt;ATOMICIDAD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En nuestro ejemplo de php, se puede implementar de varias formas, pero la que normalmente uso es hacer un try catch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="c1"&gt;// ... solo el código que interesa para el ejemplo&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$conexionBd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$factura&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Factura&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$datosDeFactura&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$factura&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalleDeFactura&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$detalle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DetalleFactura&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;factura&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$factura&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;producto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Producto&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'producto_id'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$inventario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Inventario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$inventario&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;producto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Producto&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$detalle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'producto_id'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nv"&gt;$inventario&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$conexionBd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$conexionBd&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nv"&gt;$e&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;Agregando estas líneas de código estamos asegurando que la factura se crea con los 3 productos enviados, o no se crea la factura, y&lt;br&gt;
la integridad de los datos está asegurada sin datos basura en la base.&lt;/p&gt;

</description>
      <category>database</category>
    </item>
    <item>
      <title>Encontrando errores en el código con git bisect</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Tue, 18 May 2021 12:29:17 +0000</pubDate>
      <link>https://dev.to/marceloandrade/encontrando-errores-en-el-codigo-con-git-bisect-9cb</link>
      <guid>https://dev.to/marceloandrade/encontrando-errores-en-el-codigo-con-git-bisect-9cb</guid>
      <description>&lt;p&gt;Cuando se usa &lt;code&gt;git&lt;/code&gt; en un equipo de trabajo a veces alguien del grupo puede introducir un error en el código que no fue descubierto por los tests ni en la revisión de usuario, y se publica el error al sistema de producción. El momento que se recibe el reporte del error en producción generalmente desde el último despliegue hay varios commits hechos por varios desarrolladores, para encontrar dónde se introdujo el error podemos usar &lt;code&gt;git bisect&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/docs/git-bisect"&gt;&lt;code&gt;git bisect&lt;/code&gt;&lt;/a&gt; de acuerdo a su documentación nos indica que realiza una búsqueda binaria para encontrar el commit que introdujo un bug. Una búsqueda binaria es un algoritmo en el que se va reduciendo la búsqueda de un commit eliminando posibles commits "buenos" o "malos".&lt;/p&gt;

&lt;p&gt;La búsqueda de nuestro bug de ejemplo puede comenzar de la siguiente manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect start &lt;span class="c"&gt;# Permite iniciar la búsqueda&lt;/span&gt;
git bisect bad   &lt;span class="c"&gt;# Indica que la versión actual es la incorrecta&lt;/span&gt;
git bisect good 4f0dfa72bcdc2ba489629949883392aaa3a4e43b   &lt;span class="c"&gt;# Es la referencia al último commit correcto puede ser un tag on un branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez que tenemos al menos un commit bueno y uno malo, git bisect seleccionara un commit en el medio del rango para verificación. Nos mostrará un mensaje que indica el commit que está en el área de trabajo cuantas revisiones quedan por hacer y un estimado de pasos hasta encontrar el error.&lt;/p&gt;

&lt;p&gt;Cuando estemos en este paso tenemos que verificar el error existe en ese commit, si no existe, ejecutamos &lt;code&gt;git bisect good&lt;/code&gt; y git bisect nos dará un nuevo commit para probar. En este paso podemos ejecutar tests, probar manualmente, ejecutar algún proceso que verifique si hay no error o simplemente ver el código. Si es un commit malo se ejecuta &lt;code&gt;git bisect bad&lt;/code&gt; hasta que git bisect indique el mensaje que un commit es el primer bad commit (&lt;code&gt;first bad commit&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Al final de la sesión de trabajo se ejecuta &lt;code&gt;git bisect reset&lt;/code&gt; para volver al branch que estuvimos inicialmente.&lt;/p&gt;

&lt;p&gt;Hay también una forma automática de verificar si un commit es válido, usando &lt;code&gt;git bisect run your_script arguments&lt;/code&gt;. El script denominado your_script debe retornar un código de salida 0 para marcar un commit como bueno, y un código entre 1 y 127 (exceptuando 125) cuando el commit es malo. El 125 se usa para cuando no se puede probar y lo marca como skipped.&lt;/p&gt;

&lt;p&gt;Si hay alguna duda, por favor no duden en suscribirse y responder directamente a mis emails.&lt;/p&gt;

</description>
      <category>git</category>
      <category>tip</category>
    </item>
    <item>
      <title>Verificar rangos de fechas en PostgreSQL</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Sat, 08 May 2021 22:13:58 +0000</pubDate>
      <link>https://dev.to/marceloandrade/verificar-rangos-de-fechas-en-postgresql-201j</link>
      <guid>https://dev.to/marceloandrade/verificar-rangos-de-fechas-en-postgresql-201j</guid>
      <description>&lt;p&gt;Mi motor de base de datos favorito para proyectos nuevos es PostgreSQL o postgres. Es una base muy solida, open source, con más de 30 años de desarrollo, se ha ganado una gran reputación por su confiabilidad, robustez y desempeño.&lt;/p&gt;

&lt;p&gt;Hoy les quiero compartir un pequeño tip que me ha servido mucho en un  par de proyectos, en los cuales se requiere mantener un registro de datos históricos y que no debe haber superposición de un valor en un mismo rango de fechas. Por ejemplo, el valor del IVA generalmente es fijo, pero hubo un tiempo en que cambió. Una tabla para manejar estos cambios en el tiempo sería de la forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;historico_iva&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;empresa_id&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;desde&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;hasta&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;porcentaje_iva&lt;/span&gt; &lt;span class="nb"&gt;numeric&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;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;Esta validación de datos se podría realizar a nivel de aplicación al verificar que no haya 2 valores de IVA para la misma fecha, por ejemplo digamos que el 1 de junio cambia el valor al 10% en la tabla habría los siguientes registros:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;empresa_id&lt;/th&gt;
&lt;th&gt;desde&lt;/th&gt;
&lt;th&gt;hasta&lt;/th&gt;
&lt;th&gt;porcentaje_iva&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2000-01-01&lt;/td&gt;
&lt;td&gt;2021-05-31&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2021-06-01&lt;/td&gt;
&lt;td&gt;null&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Para buscar que valor de iva debo aplicar en una fecha específica puedo usar la consulta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;porcentaje_iva&lt;/span&gt; 
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;historico_iva&lt;/span&gt; 
&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;empresa_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
&lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="k"&gt;current_date&lt;/span&gt; &lt;span class="k"&gt;between&lt;/span&gt; &lt;span class="n"&gt;desde&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;coalesce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Infinity'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta debe devolver siempre un solo valor, pero por cualquier error de programación o al editar datos en la base directamente en el registro 2 le pongo 2021-05-31 en la fecha desde, el día 31 de mayo no se sabría si fue 10 o 12 el IVA ya que la consulta devuelve 2 valores. O también que la fecha desde sea mayor a la fecha hasta en cuyo caso nunca retornaría un valor.&lt;/p&gt;

&lt;p&gt;Para evitar este inconveniente se puede agregar un par de checks a nivel de base de datos, y para esto postgres ayuda mucho con una extensión para manejo de este tipo de validaciones denominada &lt;code&gt;btree_gist&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para nuestro ejemplo se debe agregar los siguientes CHECKs en la tabla:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--- activa la extension btree_gist&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;btree_gist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;--- verifica que la fecha desde sea menor a la fecha hasta&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;porcentaje_iva&lt;/span&gt; 
    &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;"desde"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;"hasta"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-------- evita superposición de rango de fechas en una misma empresa&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;porcentaje_iva&lt;/span&gt; 
    &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;no_sobreponer_fechas_iva&lt;/span&gt; 
        &lt;span class="n"&gt;EXCLUDE&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;GIST&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;empresa_id&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;daterange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"desde"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coalesce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"hasta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Infinity'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'[]'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto implica que al tratar de crear un registro de la misma empresa, que tenga fechas sobrepuestas&lt;br&gt;
la base de datos no lo va a permitir y generará un error.&lt;/p&gt;

</description>
      <category>postgres</category>
    </item>
    <item>
      <title>Cómo utilizar symplify/vendor-patches en proyectos php?</title>
      <dc:creator>Marcelo Andrade R.</dc:creator>
      <pubDate>Fri, 30 Apr 2021 13:59:03 +0000</pubDate>
      <link>https://dev.to/marceloandrade/como-utilizar-symplify-vendor-patches-en-proyectos-php-3455</link>
      <guid>https://dev.to/marceloandrade/como-utilizar-symplify-vendor-patches-en-proyectos-php-3455</guid>
      <description>&lt;p&gt;Es posible que alguna vez hayan encontrado un bug en una dependencia de un proyecto de php que utiliza composer, y el arreglo es simple y lo único que se requiere es cambiar 1 o 2 líneas de código en el paquete referenciado es decir en &lt;code&gt;/vendor/usuario/paquete-con-error&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Como buen ciudadano del mundo open source, lo primero que se debe hacer es abrir un issue y crear un pull request con los cambios en el proyecto dependencia para que el dueño lo pueda aceptar y se arregle para todos los usuarios de ese paquete, pero no vamos a negar que este proceso toma bastante tiempo, y si necesitamos arreglar lo más pronto hay otras opciones.&lt;/p&gt;

&lt;p&gt;Puedes crear un fork del proyecto en tu github y usar ese url de github en la version de composer.json, pero estarías tomando una responsabilidad manual de actualizar y aplicar el cambio cada vez que haya actualizaciones. Se puede copiar el paquete localmente que es más rápido pero con esto ya no hay actualizaciones.&lt;/p&gt;

&lt;p&gt;O la mejor opción se puede usar "composer patches".&lt;/p&gt;

&lt;p&gt;Hace un tiempo estaba trabajando en un proyecto laravel con el paquete de administración nova, y un addon para manejo de archivos &lt;code&gt;infinety-es/nova-filemanager&lt;/code&gt; el paquete funcionaba muy bien con archivos públicos, pero para mi proyecto necesitaba guardar los archivos en un bucket privado de S3 y para descargarlos debía generar una url temporal con un tiempo de expiración máximo.&lt;/p&gt;

&lt;p&gt;Analizando el código del paquete encontré 2 lugares donde se generaba la url del archivo para descarga en el archivo fuente &lt;code&gt;src/Http/Services/NormalizeFile.php&lt;/code&gt; en la función &lt;a href="https://github.com/InfinetyEs/Nova-Filemanager/blob/master/src/Http/Services/NormalizeFile.php#L53"&gt;toArray&lt;/a&gt; y en la función &lt;a href="https://github.com/InfinetyEs/Nova-Filemanager/blob/master/src/Http/Services/NormalizeFile.php#L148"&gt;getImage&lt;/a&gt; lo único que había que hacer es realizar el siguiente cambio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--- /dev/null
&lt;/span&gt;&lt;span class="gi"&gt;+++ ../src/Http/Services/NormalizeFile.php
&lt;/span&gt;&lt;span class="p"&gt;@@ -50,7 +50,7 @@&lt;/span&gt;
             'mime' =&amp;gt; $this-&amp;gt;getCorrectMimeFileType(),
             'path' =&amp;gt; $this-&amp;gt;storagePath,
             'size' =&amp;gt; $this-&amp;gt;getFileSize(),
&lt;span class="gd"&gt;-            'url'  =&amp;gt; $this-&amp;gt;cleanSlashes($this-&amp;gt;storage-&amp;gt;url($this-&amp;gt;storagePath)),
&lt;/span&gt;&lt;span class="gi"&gt;+            'url'  =&amp;gt; $this-&amp;gt;cleanSlashes($this-&amp;gt;storage-&amp;gt;temporaryUrl($this-&amp;gt;storagePath, '+5 minutes')),
&lt;/span&gt;             'date' =&amp;gt; $this-&amp;gt;modificationDate(),
             'ext'  =&amp;gt; $this-&amp;gt;file-&amp;gt;getExtension(),
         ]);
&lt;span class="p"&gt;@@ -145,7 +145,7 @@&lt;/span&gt;
     private function getImage($mime, $extension = false)
     {
         if (Str::contains($mime, 'image') || $extension == 'svg') {
&lt;span class="gd"&gt;-            return $this-&amp;gt;storage-&amp;gt;url($this-&amp;gt;storagePath);
&lt;/span&gt;&lt;span class="gi"&gt;+            return $this-&amp;gt;storage-&amp;gt;temporaryUrl($this-&amp;gt;storagePath, '+5 minutes');
&lt;/span&gt;         }

         $fileType = new FileTypesImages();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cómo se cambia esas 2 líneas en /vendor?
&lt;/h2&gt;

&lt;p&gt;Se hace en 4 simples pasos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instalar el paquete que controla los parches
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require cweagans/composer-patches symplify/vendor-patches --dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Se crea una copia del archivo a cambiar en /vendor por la extensión &lt;code&gt;.old&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Por ejemplo en mi caso cambie &lt;code&gt;vendor/infinety-es/nova-filemanager/src/Http/Services/NormalizeFile.php&lt;/code&gt; a&lt;br&gt;
&lt;code&gt;vendor/infinety-es/nova-filemanager/src/Http/Services/NormalizeFile.php.old&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Abrir el archivo original &lt;code&gt;vendor/infinety-es/nova-filemanager/src/Http/Services/NormalizeFile.php&lt;/code&gt; y realizar los cambios necesarios. Se verifica que los cambios funcionen ya que solo el archivo &lt;code&gt;*.php&lt;/code&gt; funciona no el &lt;code&gt;*.php.old&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generar el parche usando el comando:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vendor/bin/vendor-patches generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;La herramienta de symplify genera todos los parches en el directorio &lt;code&gt;/patches/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ls -l patches
.rw-r--r-- 883 marcelo 30 Apr  7:16 infinety-es-nova-filemanager-src-http-services-normalizefile-php.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y también genera la configuración de parches al composer.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ...
    "extra": {
        "laravel": [],
        "patches": {
            "infinety-es/nova-filemanager": [
                "patches/infinety-es-nova-filemanager-src-http-services-normalizefile-php.patch"
            ]
        }
    },
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y eso es todo, la siguiente vez que realicen &lt;code&gt;composer install&lt;/code&gt;, el parche se aplica automáticamente.&lt;/p&gt;

&lt;p&gt;Referencias: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tomasvotruba.com/blog/2020/07/02/how-to-patch-package-in-vendor-yet-allow-its-updates/"&gt;How to Patch a Package in Vendor, Yet Allow its Updates | Tomas Votruba&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
