<?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: Lautaro Celli</title>
    <description>The latest articles on DEV Community by Lautaro Celli (@akalautaro).</description>
    <link>https://dev.to/akalautaro</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%2F561735%2F5e2b171d-bc1a-4b46-adc2-7042e6bb7877.png</url>
      <title>DEV Community: Lautaro Celli</title>
      <link>https://dev.to/akalautaro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akalautaro"/>
    <language>en</language>
    <item>
      <title>Cómo hackear tu seniority en IT (sin aprender otro framework)</title>
      <dc:creator>Lautaro Celli</dc:creator>
      <pubDate>Mon, 08 Sep 2025 19:38:04 +0000</pubDate>
      <link>https://dev.to/akalautaro/como-hackear-tu-seniority-en-it-sin-aprender-otro-framework-30em</link>
      <guid>https://dev.to/akalautaro/como-hackear-tu-seniority-en-it-sin-aprender-otro-framework-30em</guid>
      <description>&lt;h3&gt;
  
  
  Introducción
&lt;/h3&gt;

&lt;p&gt;Cuando empecé a acercarme al mundo IT, todo me resultaba abrumador: lenguajes, frameworks, paradigmas, herramientas… parecía un universo infinito.&lt;/p&gt;

&lt;p&gt;En el año 2018/2019, quise aprender a programar en Python, y me encontré con cursos sobre Python y Python3 🤯. ¿Si quiero aprender python tengo que ir 1 por 1? ¿Es como una saga de películas? ¿Puedo empezar por el 3 o me va a faltar &lt;em&gt;lore&lt;/em&gt; más adelante? 🤔. Parece chiste pero es anécdota: tuve que consultar con un amigo con cuál empezar 😅.&lt;/p&gt;

&lt;p&gt;He de decir que conforme avanzaron los años, esta sensación de que IT es un universo enorme que nunca te acercas a terminar de conocer no aflojó, creo que me volvió a pasar con todo el boom de la IA y los LLMs, pero esa es otra conversación o &lt;em&gt;blogpost&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Con el tiempo, trabajando primero como Help-Desk y después como Data Engineer (o Data Developer), entendí que &lt;em&gt;"nunca"&lt;/em&gt; iba a poder abarcar todo lo técnico. Siempre habría nuevas tecnologías y frameworks que no alcanzaría a dominar.&lt;/p&gt;

&lt;p&gt;Lo que sí descubrí, casi de forma indirecta, es que había también otras formas de crecer: las actitudes, las soft-skills. No siempre son visibles ni medibles, pero hacen una gran diferencia en cómo avanzamos en seniority.&lt;/p&gt;

&lt;p&gt;En este post comparto las que, desde mi experiencia, más me ayudaron en ese camino.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ownership
&lt;/h3&gt;

&lt;p&gt;Tomar Ownership es hacerse responsable no sólo de las tareas o los tickets que nos asignan, sino también del impacto que estas tienen. Significa anticiparse a problemas, buscar soluciones y no esperar a que alguien más lo resuelva. Creo que a todos se nos habrá pasado en algún momento el pensamiento de "esto no es mi problema" o "X cosa es un problema no contemplado en mi ticket Y, será problema de otro en el próximo sprint". Es importante pasar de "no es mi problema" a "¿cómo puedo ayudar a resolverlo?". Y esto aplica tanto a nuestras propias tareas como a las de nuestros compañeros. &lt;strong&gt;Personalmente&lt;/strong&gt; creo que este es un diferencial enorme que podemos ofrecer y que sin dudas marca un gran salto en cuanto a crecimiento profesional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gestión de prioridades
&lt;/h3&gt;

&lt;p&gt;En IT, por lo general, siempre van a haber más tareas de las que podemos cubrir, por esto es importantísimo aprender a distinguir entre lo &lt;em&gt;urgente&lt;/em&gt; y lo &lt;em&gt;importante&lt;/em&gt;, y cuándo priorizar cada cosa. Puede que en un momento se caiga producción y tengamos que resolver urgencias en vivo, mientras que en otras ocasiones puede ser necesario priorizar una mejora "estructural" justificando el por qué no se puede seguir postergando.&lt;/p&gt;

&lt;p&gt;Aprender a justificar por qué algo que no es urgente igual merece prioridad es parte clave del crecimiento. Si gestionamos bien las prioridades, también estaremos gestionando mejor nuestro tiempo&lt;/p&gt;

&lt;h3&gt;
  
  
  Comunicación efectiva
&lt;/h3&gt;

&lt;p&gt;No alcanza con &lt;strong&gt;saber&lt;/strong&gt;; es igual de importante &lt;em&gt;saber comunicar&lt;/em&gt;. Ser claro en un mail, en un mensaje de Slack, o explicando en una reunión, evita malentendidos y acelera proyectos. Es de esas habilidades que vamos adquiriendo y aprendiendo sobre la marcha y con la experiencia, más allá de que hay algunas buenas prácticas.&lt;/p&gt;

&lt;p&gt;Desde mi punto de vista, y en conjunto con el ownership, creo que son puntos claves para destacar como profesionales, más allá del puesto que ocupemos y seniority que tengamos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Colaboración
&lt;/h3&gt;

&lt;p&gt;Es importante la colaboración con compañeros de diferente seniority, y es válido en ambos sentidos. Si tenemos cierta experiencia con algún tema es importante ofrecer apoyo a compañeros que quizás no lo tienen tan claro, y a su vez si recién estamos comenzando está buenísimo empezar a preguntar, de esta forma se arma una suerte de círculo de retroalimentación super valioso. &lt;strong&gt;El conocimiento compartido escala más que el individual.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Curiosidad / Búsqueda de desafíos
&lt;/h3&gt;

&lt;p&gt;Cerrar un ticket y olvidarnos a veces puede ser tentador, pero casi cualquier cosa que hagamos tiene oportunidad de mejora o un plus que podemos sumar. Si una tarea de 3 horas nos llevó 2, está bueno aprovechar ese restante en investigar si no hay una solución alternativa, o mismo proponer una mejora a soluciones ya existentes. Con cosas que están a la mano podemos estar sumando muchísimo, tanto a la calidad de lo que entregamos como mismo a nuestro aprendizaje. Es importante sostener esta curiosidad porque el no quedarse quieto te empuja siempre al próximo nivel. Además, esta actitud genera mucha visibilidad: te ven como alguien que propone y no solo como alguien que cierra tickets en Jira.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cierre
&lt;/h3&gt;

&lt;p&gt;Estas actitudes no dependen de un framework ni de la última herramienta de moda en tecnología. Son hábitos que se pueden empezar a practicar desde cualquier rol y nivel de experiencia, y que en mi caso fueron clave para crecer en seniority.&lt;/p&gt;

&lt;p&gt;Me interesa saber: ¿qué otras actitudes te ayudaron a vos en tu camino? ¿Qué agregarías a la lista?&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
      <category>discuss</category>
      <category>learning</category>
    </item>
    <item>
      <title>Implementando Databricks Asset Bundles sin morir en el intento</title>
      <dc:creator>Lautaro Celli</dc:creator>
      <pubDate>Thu, 29 May 2025 03:39:23 +0000</pubDate>
      <link>https://dev.to/akalautaro/implementando-databricks-asset-bundles-sin-morir-en-el-intento-17ih</link>
      <guid>https://dev.to/akalautaro/implementando-databricks-asset-bundles-sin-morir-en-el-intento-17ih</guid>
      <description>&lt;h3&gt;
  
  
  Índice
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Introducción&lt;/li&gt;
&lt;li&gt;¿Qué es Databricks Asset Bundles?&lt;/li&gt;
&lt;li&gt;Antes de DABs, ¿es tan caótico?&lt;/li&gt;
&lt;li&gt;Durante: implementando DABs en un proyecto productivo&lt;/li&gt;
&lt;li&gt;Después de DABs: así se ve el paraíso&lt;/li&gt;
&lt;li&gt;¿Tips &amp;amp; tricks?&lt;/li&gt;
&lt;li&gt;Conclusión&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Aclaración: esta es mi primera experiencia trabajando en Databricks, puede que más de una cosa pueda hacerse mejor y existan mejores prácticas, lo que voy a escribir es una experiencia propia.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Hace unos meses empecé a trabajar con Databricks, en un proyecto "chico" para una empresa grande (consultoras ftw ¿?). Este proyectito era una pavadita: consumir data de archivos excel (para sorpresa de nadie), pegarle a una API, un par de transformaciones y volcar los datos en una Delta table. Bastante sencillo, así que resolvimos con un par de notebooks orquestadas por un Workflow en Databricks y salió andando. Hasta ahí, sencillísimo. El "problema" (o el desafío) vino cuando tuvimos que empezar a customizar bastante el pipeline, de originalmente 2 notebooks, para que usuarios de otros países puedan pasar a utilizar la herramienta que habíamos desarrollado. El país con el que trabajamos pasó de 1 a 6, se sumaron validaciones, nuevas reglas de negocio, diferencias entre ambientes y APIs para cada país, features nuevas como notificaciones custom directamente al usuario, export de resultados, nuevos flujos de datos, y un largo etcétera.&lt;/p&gt;

&lt;p&gt;A esta altura, el workflow ya no era un único con 2 notebooks que funcionaban para un solo país. Ahora teníamos algo un poco más complejo, con parametrizaciones de por medio, validaciones de datos, notificaciones según estado y también nuevos workflows. Más allá de que los requerimientos estaban resueltos y teníamos algo funcional, ahora vinieron nuevos &lt;em&gt;problemas&lt;/em&gt;: varias personas del equipo trabajando sobre los workflows, realizando modificaciones y teniendo poca o &lt;strong&gt;nula trazabilidad de los cambios en los pipelines&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por suerte, la tecnología generalmente suele ofrecernos soluciones a este tipo de problemas comunes y así, tarde aunque aún a tiempo, implementamos &lt;strong&gt;Databricks Asset Bundles&lt;/strong&gt; en nuestro proyecto.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es Databricks Asset Bundles?
&lt;/h2&gt;

&lt;p&gt;Databricks Asset Bundles (DABs) es una herramienta cuyo propósito es facilitar la &lt;strong&gt;adopción de las mejores prácticas de la ingeniería de software&lt;/strong&gt; (versionado de código, testing, CI/CD, despliegue en distintos ambientes, entre otras) a p*&lt;em&gt;royectos de ciencia de datos e IA&lt;/em&gt;&lt;em&gt;, facilitando el trabajo colaborativo en proyectos en desarrollo. Según **Databricks&lt;/em&gt;*: &lt;em&gt;"A bundle is an end-to-end definition of a project, including how the project should be structured, tested, and deployed"&lt;/em&gt;. A grandes rasgos, lo que permite DABs es definir cualquier recurso de Databricks en archivos &lt;code&gt;.yaml&lt;/code&gt; en nuestro repositorio, bajo el enfoque infrastructure-as-code (IaC).&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Antes de DABs, ¿es tan caótico?
&lt;/h2&gt;

&lt;p&gt;Si bien Asset Bundles, según la documentación, está pensado para proyectos &lt;strong&gt;complejos&lt;/strong&gt; (vaya a saber uno la definición de complejo en este contexto), en nuestro caso sin ser necesariamente un proyecto grande se hizo necesario una vez que el número de workflows y personas trabajando sobre estos dejó de ser 1.&lt;/p&gt;

&lt;p&gt;En nuestro caso, el principal problema de no tener implementado Asset Bundles estaba en no poder manejar el &lt;strong&gt;versionado de los workflows&lt;/strong&gt;. Aunque la UI es bastante noble para desarrollar nuevos workflows, no existe la posibilidad de ver &lt;strong&gt;qué cambios se fueron haciendo&lt;/strong&gt; ni se tiene registro de eso, aumentando la posibilidad de &lt;strong&gt;discrepancias entre pipelines&lt;/strong&gt;, no pudiendo hacer &lt;strong&gt;code-reviews&lt;/strong&gt;, sin poder tener un pantallazo general del código teniendo que ver los detalles &lt;strong&gt;tarea por tarea&lt;/strong&gt;, y otros &lt;em&gt;demases&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Puede parecer que no, pero el sólo hecho de &lt;strong&gt;no tener versionado&lt;/strong&gt; para los workflows fue motivo suficiente para avanzar con DABs, a pesar de que no tenía mucha experiencia en Databricks ni tampoco en IaC ni CI/CD (&lt;strong&gt;mucha prueba y error&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Flujo de trabajo antes de DABs (principalmente en workflows):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desarrollo de código, trackeado en un repositorio&lt;/li&gt;
&lt;li&gt;Modificaciones en workflows en la UI, aplicando cambios 1 a 1 utilizando la interfaz. Si tenes workflows similares tenes que ir uno por uno en la UI, modificando 1 a 1, incluso tarea por tarea.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Durante: implementando DABs en un proyecto productivo
&lt;/h2&gt;

&lt;p&gt;En nuestro caso, no necesitamos la parte de despliegue de clusters ni hacer muchas cosas raras, sólo precisamos -nuevamente- &lt;strong&gt;versionado de workflows&lt;/strong&gt;, sumado a la validación y despliegue continuos de estos.&lt;/p&gt;

&lt;p&gt;Debo decir que la documentación oficial de Databricks sobre cómo implementar DABs es bastante clara, aunque hubieron varias cuestiones no mencionadas explícitamente con las que me estuve peleando algunas horas hasta que tuve éxito.&lt;/p&gt;

&lt;h3&gt;
  
  
  Primero lo primero
&lt;/h3&gt;

&lt;p&gt;Debemos tener instalada y configurada la CLI de Databricks. Se puede chequear fácilmente con&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;databricks &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez listo esto, es tan fácil como hacer&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;databricks bundle init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y seguir los pasos del interactivo, que no es más que nombrar el bundle y elegir el template a utilizar. La estructura del bundle será la siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;README.md  databricks.yml  fixtures  pytest.ini  requirements-dev.txt  resources  scratch  setup.py  src  tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mientras que &lt;code&gt;databricks.yml&lt;/code&gt; se ve algo así&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle:
  name: dabs101

include:
  - resources/*.yaml

targets:
  dev:
    # The default target uses 'mode: development' to create a development copy.
    # - Deployed resources get prefixed with '[dev my_user_name]'
    # - Any job schedules and triggers are paused by default.
    # See also https://docs.databricks.com/dev-tools/bundles/deployment-modes.html.
    mode: development
    default: true
    workspace:
      host: https://&amp;lt;development-workspace-url&amp;gt;

  prod:
    mode: production
    workspace:
      host: https://&amp;lt;production-workspace-url&amp;gt;
    permissions:
      - user_name: user1@mail.com
        level: CAN_MANAGE
    run_as:
      user_name: user2@mail.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este acotado yaml hay un par de variables a resaltar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;target: diferentes ambientes. Podemos definir más de un ambiente y, a su vez, utilizar distintos parámetros. Esto es útil para hacer despliegues en ambientes de dev o QA y hacer pruebas antes de un despliegue en prod (el que esté libre de pecado que tire la primera piedra).&lt;/li&gt;
&lt;li&gt;include: ruta de los recursos incluidos en el bundle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Para ver todas las posibilidades de configuración ver &lt;a href="https://docs.databricks.com/aws/en/dev-tools/bundles/settings" rel="noopener noreferrer"&gt;Databricks Asset Bundle configuration&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ahora si, vamos a lo importante: ¿cómo se vería la estructura de un workflow en yaml?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resources:
  jobs:
    foo_job:
      name: foo_job
      max_concurrent_runs: 1
      schedule:
        quartz_cron_expression: 12 0 0 * * ?
        timezone_id: America/Mexico_City
        pause_status: UNPAUSED
      tasks:
        - task_key: foo_task
          notebook_task:
            notebook_path: the/notebook/path
            source: GIT
          existing_cluster_id: existing_cluster_id
      git_source:
        git_url: git_url
        git_provider: git_provider
        git_branch: git_branch
      queue:
        enabled: true
      parameters:
        - name: parameter1
          default: value1
        - name: parameter2
          default: value2
        - name: parameter3
          default: ""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Pequeño truquito:&lt;/em&gt;&lt;/strong&gt; si bien el yaml es sencillo de leer y saber qué hace, para desarrollar a mi me da bastante &lt;strong&gt;fiaca&lt;/strong&gt;. Por suerte, se pueden desarrollar los workflows a través de la UI de Databricks y de ahí extraer el código fuente en yaml, json o código python.&lt;/p&gt;

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

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

&lt;p&gt;Para la parte interesante que vendría siendo el despliegue del bundle, la CLI de Databricks dispone de 3 comandos bastante piolas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;databricks bundle validate &lt;span class="nt"&gt;--target&lt;/span&gt; prod  &lt;span class="c"&gt;# para validar el bundle e  identificar errores y warnings&lt;/span&gt;
databricks bundle summary &lt;span class="nt"&gt;--target&lt;/span&gt; prod   &lt;span class="c"&gt;# resumen de lo que se va a desplegar (nuevo y/o asociado a recursos existentes)&lt;/span&gt;
databricks bundle deploy &lt;span class="nt"&gt;--target&lt;/span&gt; prod    &lt;span class="c"&gt;# deploy del bundle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hasta acá todo muy bueno para desplegar nuevos recursos, pero en nuestro caso los &lt;strong&gt;workflows ya existían&lt;/strong&gt; pues habían sido &lt;strong&gt;desarrollados utilizando la UI&lt;/strong&gt; de Databricks y al hacer el deploy los workflows se volvían a crear, teniendo jobs duplicados. &lt;/p&gt;

&lt;p&gt;Me pelee bastante con comandos, archivos de metadata, entradas en los yamls y varias horas de trabajo, y al final la magia la hacía el comando &lt;code&gt;bind&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;databricks bundle deployment unbind &lt;span class="nt"&gt;--target&lt;/span&gt; prod workflow_unique_name   &lt;span class="c"&gt;# necesario si el recurso ya está asociado a un nuevo id en el bundle&lt;/span&gt;
databricks bundle deployment &lt;span class="nb"&gt;bind&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; prod workflow_unique_name workflow_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con &lt;code&gt;bind&lt;/code&gt; lo que hacemos es decirle a Databricks que el &lt;strong&gt;recurso existente de id X ahora pasa a ser gestionado por Asset Bundles&lt;/strong&gt;: &lt;em&gt;magia&lt;/em&gt;. Un detalle, importante prestar atención a la flag &lt;code&gt;--target&lt;/code&gt;, ya que si no especifican lo hace en la por defecto y les puede pasar como a mi que no entienden por qué se sigue duplicando el workflow en prod cuando lo bindearon al entorno de dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  Después de DABs: así se ve el paraíso
&lt;/h2&gt;

&lt;p&gt;Bueno, tampoco para tanto. Como dije antes, nuestro principal problema ya no es tal, ahora tenemos versionado de los workflows.&lt;/p&gt;

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

&lt;p&gt;Cabe destacar que mi motor fueron pura y exclusivamente los workflows,   pero podemos implementar DABs para gestionar muchos más recursos en Databricks: worfklows, pipelines de Delta Live Tables, creación y despliegue de clusters, etc. Yo aproveché la inquietud para poder testear la herramienta por primera vez, aunque seguramente a partir de acá siga profundizando.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Tips &amp;amp; tricks?
&lt;/h2&gt;

&lt;p&gt;En mis intentos por implementar DABs me crucé con varias cuestiones, un resumen para que dentro de lo posible se ahorren un poco más de tiempo que yo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;databricks bundle generate&lt;/code&gt;&lt;/strong&gt;: en la teoría, este comando genera el &lt;code&gt;.yaml&lt;/code&gt; de un recurso ya existente. En mi caso, los workflows estaban apuntados a notebooks conectados a un repositorio de Azure DevOps, por lo que las rutas eran relativas al repositorio. Por este motivo, el comando arrojaba error de path o formato de path incorrecto. Mi solución fue como comenté más arriba, directamente crear los archivos &lt;code&gt;.yaml&lt;/code&gt; exportando el código de cada workflow, un poco más manual pero igual de válido.&lt;/li&gt;
&lt;li&gt;Jobs duplicados: probé de diferentes maneras asociar los recursos existentes mediante nombres, id, rutas, etc., y si se te duplican los jobs es porque no están asociados correctamente al bundle. Hay 2 opciones: mantener el nuevo job gestionado por bundles y borrar el anterior (se pierde el run history) o bindear manualmente los recursos al bundle
&lt;strong&gt;&lt;code&gt;databricks bundle deployment bind/unbind&lt;/code&gt;&lt;/strong&gt;: importante prestar atención a qué target estamos apuntando. Me pasó de tener configurado por defecto el target dev, por lo que al hacer bind seguía duplicando jobs, atención al flag --target. Algo importante es que si ya desplegaron el bundle y no están correctamente asociados los recursos, van a tener que hacer el unbind de cada recurso.&lt;/li&gt;
&lt;li&gt;Aprovechar los pipelines de CI/CD: el despliegue de los bundles es idempotente, cada vez que se hace deploy se comparan los hashes entre los recursos desplegados y los del bundle, en caso de que no haya modificaciones no vuelve a desplegar el recurso, por lo que se puede dejar previsto la validación y despliegue del bundle en nuestro pipeline de CI/CD del repo sin preocuparnos por estar sobrescribiendo nada innecesariamente.&lt;/li&gt;
&lt;li&gt;Una vez que los workflows pasan a ser gestionados por bundles pasa a bloquearse la edición en la UI, reforzando el concepto de IaC y evitar sobrescribirlos manualmente. Esto puede ser bastante fiaca si estamos en una etapa de constantes modificaciones donde sería más sencillo iterar trabajando en la UI que sobre los yaml, aunque siempre está disponible la opción de quitar el recurso del bundle para poder editar sobre la UI y luego volver a agregarlo al bundle (aunque no tendría tanto sentido pues iría contra el por qué de implementar DABs, pero la opción está).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Como cierre unas últimas preguntas y respuestas que me surgieron en este proceso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;¿Implementaría DABs en otros proyectos?&lt;/strong&gt; Definitivamente si. Poder gestionar el despliegue completo desde un único archivo (o un conjunto de archivos yaml) me parece un puntazo a favor, además de poder tener todo esto versionado y trackeado en un repositorio&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;¿Lo implementaría en un proyecto desde 0?&lt;/strong&gt; Si y no. Lo más fiaca es lo que comentaba más arriba sobre el blocker que significa en la UI para los workflows. Creo que se podría implementar desde 0 en el proyecto, pero para recursos que necesitemos iterar bastante como puede ser un workflow o un pipeline en escenarios tempranos de un desarrollo podrían sumarse al último o cuando tengan un grado de madurez suficiente como para no necesitar estar aplicando cambios constantemente en archivos yaml.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;La comunicación del bundle no es bidireccional&lt;/strong&gt;: si modificamos algo en la UI no se modifica automáticamente en el bundle. Es importante tener esto en cuenta pues si modificamos recursos a través de la UI y no reflejamos los cambios en la definición de nuestro bundle, cada vez que hagamos un deploy vamos a pisar la configuración según lo que tengamos definido. Debería poder implementarse algún pipeline para verificar estos cambios de estado en los recursos, aunque desconozco.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;Para cerrar, nuevamente aclarar que esta fue la primera vez que trabajo con Databricks/Databricks Asset Bundles, por lo que muchas cosas seguro puedan hacerse de mejor manera. La idea no es que se tome esto como una guía per sé, si no que mi experiencia sirva de referencia para personas que por ahí estén en una situación parecida a la que estaba yo hace unos días sin tener mínima idea de cómo implementar la herramienta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Algunos links útiles
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.databricks.com/aws/en/dev-tools/bundles/" rel="noopener noreferrer"&gt;What are Databricks Asset Bundles?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.databricks.com/aws/en/dev-tools/bundles/settings" rel="noopener noreferrer"&gt;Databricks Asset Bundle configuration&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.databricks.com/aws/en/dev-tools/cli/bundle-commands" rel="noopener noreferrer"&gt;bundle command group&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.databricks.com/aws/en/release-notes/dev-tools/bundles" rel="noopener noreferrer"&gt;Databricks Asset Bundles feature release notes&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.databricks.com/aws/en/dev-tools/ci-cd/best-practices" rel="noopener noreferrer"&gt;Best practices and recommended CI/CD workflows on Databricks&lt;/a&gt;&lt;/p&gt;

</description>
      <category>databricks</category>
      <category>dataengineering</category>
      <category>cicd</category>
      <category>azure</category>
    </item>
    <item>
      <title>Aprende a programar como el presidente</title>
      <dc:creator>Lautaro Celli</dc:creator>
      <pubDate>Thu, 28 Mar 2024 23:58:09 +0000</pubDate>
      <link>https://dev.to/akalautaro/aprende-a-programar-como-un-presidente-32c1</link>
      <guid>https://dev.to/akalautaro/aprende-a-programar-como-un-presidente-32c1</guid>
      <description>&lt;p&gt;¿Queres aprender a programar como un presidente lo hace? Dejame decirte que es tu día de suerte.&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%2Fj9ajlqavnxksuugw28f2.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%2Fj9ajlqavnxksuugw28f2.png" alt="Wojak in PC" width="700" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aclaro desde ya que puede que haya un poco de título en el clickbait, pero algo de &lt;strong&gt;programación&lt;/strong&gt; y &lt;strong&gt;presidentes&lt;/strong&gt; hay.&lt;/p&gt;

&lt;p&gt;Si como yo pasas mucho tiempo en Twitter y consumís &lt;strong&gt;¿contenido político?&lt;/strong&gt; 🤔 probablemente hayas visto este tuit (o este X?) del presidente en enero de este año:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1748047057024176373-871" src="https://platform.twitter.com/embed/Tweet.html?id=1748047057024176373"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1748047057024176373-871');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1748047057024176373&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Y la verdad es que quedé un tanto sorprendido de ver que el presidente de Argentina tuiteara una captura de lo que pareciera ser Jupyter Notebook o Google Colab.&lt;/p&gt;

&lt;p&gt;Para quienes no sepan a qué me refiero cuando hablo de &lt;em&gt;notebooks&lt;/em&gt;, piénsenlo como una libreta o un cuaderno, donde en lugar de renglones tenemos &lt;em&gt;celdas&lt;/em&gt; las cuales pueden contener texto o líneas de código (puede ser python, R o Julia) que pueden ser ejecutadas y hacer cositas.&lt;/p&gt;

&lt;p&gt;La idea de este post es intentar llegar al mismo resultado del tuit utilizando python y explicar un poco el proceso (si, ya sé, escribo esto con un par de meses de delay, pero todavía tenes tiempo de aprender a programar y tuitear como lo haría el presidente antes de las elecciones del 2027 y ya le sacas ventaja).&lt;/p&gt;

&lt;p&gt;Antes de empezar, pequeño disclaimer, quiero aclarar que este post está pensado más bien para personas que no saben programar o están recién empezando, con la idea de que, si les despierta curiosidad, luego puedan profundizar ya sea en el lenguaje o las áreas que se van a mencionar o tratar de manera general en los siguientes párrafos. Como digo esto, también hay otras alternativas para llegar a los mismos resultados, ya sea utilizando alguna API o librería para extraer los datos directamente desde Youtube, alguna otra herramienta de web scraping o incluso maneras distintas de codificarlo. Ahora si, arrancamos y de base tenemos dos preguntas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;¿Qué datos necesitamos?
Por lo que vemos a simple vista, se están analizando la cantidad de visitas y likes por video, aunque tenemos otros datos que podrían llegar a ser de interés como la duración del mismo.&lt;/li&gt;
&lt;li&gt;¿De dónde sacamos los datos?
Lo primero que tenemos que hacer es identificar &lt;strong&gt;de dónde salen&lt;/strong&gt; los datos que se muestran en el tuit, en este caso lo tenemos fácil ya que refieren al evento del World Economic Forum en Davos de este año, más precisamente a los videos subidos a Youtube de este evento. Respecto a esto, hay una buena noticia y es que los videos presentados, y los que se muestran en el tuit de Milei, están todos agrupados en la siguiente playlist &lt;a href="https://www.youtube.com/playlist?list=PL7m903CwFUgkUeRB0cGc8WSNNEZ4_zAqe"&gt;Davos 2024: World Leaders &amp;amp; Special Addresses | World Economic Forum | #wef24&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Habiéndonos hecho este par de preguntas ya podemos empezar a escribir código. En mi caso, voy a usar python como lenguaje de programación y la siguientes librerías para extraer y manipular los datos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;re:&lt;/strong&gt; para utilizar expresiones regulares y extraer patrones de interés en cadenas de texto (por ejemplo, los likes aparecen como "72 k vistas", yo quiero quedarme con el número 72 y en base a eso calcular cuántos likes tiene el video, o sea 72 * 1000, para quedarme con el 72 utilizo expresiones regulares)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;json:&lt;/strong&gt; para manipular contenido en ese formato extraído directamente de la página de Youtube&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pandas:&lt;/strong&gt; una de las librerías de python más comunes para análisis de datos. La voy a utilizar para trabajar con dataframes (estructuras de datos de 2 dimensiones, similares a una tabla de SQL o a una hoja de Excel/Google Sheet), lo cual me va a permitir manipular los datos ya sea para aplicarles formato, cambiarles el tipo o directamente crear nuevos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;selenium:&lt;/strong&gt; librería utilizada para automatización de testing web, en este caso la voy a utilizar para hacer una suerte de web scraping (forma linda de decir que voy a sacar datos de una página web en este caso Youtube) y extraer los datos de manera automatizada&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;matplotlib&lt;/strong&gt;: librería para generar gráficos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el caso de re y json vienen por defecto cuando instalamos python en nuestra PC, en cambio pandas y selenium tenemos que instalarlas por nuestra cuenta. En CMD, Powershell, Bash, etc, ejecutamos los siguientes comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install pandas
pip install selenium
pip install matplotlib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Si estamos dentro de una notebook de Jupyter o Google Colab hay que agregar un "%" antes de "pip". Una vez instaladas estas librerías, ya se puede empezar a escribir código.&lt;/p&gt;

&lt;p&gt;Lo primero que hay que hacer es importar las librerías que se van a utilizar y aprovechamos para inicializar el webdriver de Selenium (que en pocas palabras es el robotito que va a hacer el trabajo de extraer la información que le indiquemos):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import re
import json
import pandas as pd
import matplotlib.pyplot as plt
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("--headless")

driver = webdriver.Chrome(options=chromeOptions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Defino 2 funciones (bloques de código que realizan una tarea en específico) que me van a servir para manipular datos que vienen de manera "sucia" o incompatible con el formato que buscamos:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def extract_duration(json_data):
    duration_iso = json_data["duration"]
    duration_seconds = 0

    if duration_iso.startswith("PT"):
        duration_iso = duration_iso[2:]
        hours_index = duration_iso.find("H")
        minutes_index = duration_iso.find("M")
        seconds_index = duration_iso.find("S")

        if hours_index != -1:
            duration_seconds += int(duration_iso[:hours_index]) * 3600
            duration_iso = duration_iso[hours_index + 1 :]

        if minutes_index != -1:
            duration_seconds += int(duration_iso[:minutes_index]) * 60
            duration_iso = duration_iso[minutes_index + 1 :]

        if seconds_index != -1:
            duration_seconds += int(duration_iso[:seconds_index])
    return duration_seconds

def convert_likes(likes_str):
    likes_str = likes_str.upper()
    if " K" in likes_str:
        like_count = float((likes_str).split(" K")[0]) * 1000
    else:
        like_count = float(likes_str)
    return like_count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;La primera función se la pedí a ChatGPT y no hice ninguna iteración, probablemente haya una mejor manera de resolver el problema de incompatibilidad.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ahora si, podemos definir el "recorrido" que va a hacer el webdriver, tomando como punto de partida la URL de la playlist&lt;br&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%2Ffjw9dfel8t6wvr8hoeg8.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%2Ffjw9dfel8t6wvr8hoeg8.png" alt="Playlist URL" width="800" height="398"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PLAYLIST_URL = (
    "https://www.youtube.com/playlist?list=PL7m903CwFUgkUeRB0cGc8WSNNEZ4_zAqe"
)

driver.get(PLAYLIST_URL)

""" 
Con las siguientes líneas de código, lo que hacemos es buscar mediante xpath 
todos los elementos que coincidan con id="video-title", y de los mismos extraemos
el título del video y el link al mismo. 
Estos datos los almacenamos en una lista de diccionarios (estructura de datos de tipo clave-valor).
"""
videos_elements = driver.find_elements("xpath", '//*[@id="video-title"]')
videos_tuple = [
    (e.get_attribute("title"), e.get_attribute("href")) for e in videos_elements
]
videos = [
    {"title": e.get_attribute("title"), "link": e.get_attribute("href")}
    for e in videos_elements
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Xpath podemos decir que es un lenguaje que nos permite buscar dentro del html de la página web. En las siguientes capturas muestro una manera sencilla de obtener el xpath de un elemento de la web&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%2Ff6r2jw0jhlyzfrry5r90.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%2Ff6r2jw0jhlyzfrry5r90.png" alt="Cómo obtener xpath" width="800" height="776"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En caso de que quieran ahondar en web scraping o este tipo de automatizaciones recomiendo que busquen más información al respecto.&lt;/p&gt;

&lt;p&gt;Ahora lo que vamos a hacer es recorrer esta lista e ingresar de manera individual a cada video mediante su link para extraer sus visitas y likes&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;df_rows = []
for v in videos:
    driver.get(v.get("link"))
    WebDriverWait(driver, 15).until(
        EC.presence_of_element_located((By.XPATH, '//*[@id="video-title"]'))
    )
    like_button = driver.find_element(
        "xpath",
        '//*[@id="top-level-buttons-computed"]/segmented-like-dislike-button-view-model/yt-smartimation/div/div/like-button-view-model/toggle-button-view-model/button-view-model/button/div[2]',
    )
    views = driver.find_element("xpath", '//*[@id="info"]/span[1]')

    script_element = driver.find_element(
        "xpath", '(//script[@type="application/ld+json"])[2]'
    )
    script_text = script_element.get_attribute("textContent")
    data = json.loads(script_text)

    resource_id = re.search(r"v=([^\&amp;amp;]+)", v.get("link")).group(1)
    like_count = convert_likes(like_button.text)
    duration = extract_duration(data)
    view_count = float(data["interactionCount"])
    video_title = v.get("title")
    df_rows.append([resource_id, view_count, like_count, duration, video_title])

driver.quit()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Una vez que tenemos esta información almacenada en una lista de listas la almacenamos en un dataframe de Pandas&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;df_youtube_statistics = pd.DataFrame(
    data=df_rows, 
    columns=["resource_id", "view_count", "like_count", "duration", "title"]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Y por último realizamos el ordenamiento según la cantidad de visitas al igual que el presidente&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;df_youtube_statistics.sort_values(
    by="view_count", ascending=False, ignore_index=True, inplace=True
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Con esto tendremos los datos de la siguiente manera&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%2F7e5yj6obh7mrj3fm60ib.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%2F7e5yj6obh7mrj3fm60ib.png" alt="Pandas dataframe output" width="791" height="508"&gt;&lt;/a&gt;&lt;br&gt;
Ahora que estamos cancheros podemos mejorar (?) el análisis y agregar alguna columna calculada, como por ejemplo la tasa de likes&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;df_youtube_statistics["likes_ratio"] = round((df_youtube_statistics["like_count"] / df_youtube_statistics["view_count"]) * 100, 2)
df_youtube_statistics["title"] = df_youtube_statistics["title"].apply(lambda x: x.split("|")[0])
df_youtube_statistics.sort_values(by="likes_ratio", ascending=False, inplace=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Feqvolgodmmec4i5crre8.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%2Feqvolgodmmec4i5crre8.png" alt="Output con columnas calculadas" width="800" height="324"&gt;&lt;/a&gt;&lt;br&gt;
O incluso agregar algunos gráficos para ver los resultados de manera más amigable&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;df_youtube_sorted_by_views = df_youtube_statistics.sort_values(by='view_count', ascending=False)
df_youtube_sorted_by_likes = df_youtube_statistics.sort_values(by='like_count', ascending=False)
df_youtube_sorted_by_ratio = df_youtube_statistics.sort_values(by='likes_ratio', ascending=False)

fig, axs = plt.subplots(1, 3, figsize=(18, 5))  # 1 fila, 3 columnas

df_youtube_sorted_by_views.plot.bar(x="title", y="view_count", ax=axs[0], color='skyblue')
axs[0].set_title('View Count')

df_youtube_sorted_by_likes.plot.bar(x="title", y="like_count", ax=axs[1], color='lightgreen')
axs[1].set_title('Like Count')

df_youtube_sorted_by_ratio.plot.bar(x="title", y="likes_ratio", ax=axs[2], color='orange')
axs[2].set_title('Like Ratio')

plt.tight_layout()

plt.savefig('youtube_statistics.png')

plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F2ejeal4zu75znihxnshb.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%2F2ejeal4zu75znihxnshb.png" alt="Campeones de la calle online" width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Viendo los resultados de los gráficos podemos concluir que la calle online es argentina papá&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%2Fwxvsedv33zsmrcf6udon.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%2Fwxvsedv33zsmrcf6udon.png" alt="Bandera Argentina" width="681" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora hablando en serio, ojalá este post haya servido como una suerte de "guía" para experimentar con python y en el mejor de los casos haya despertado curiosidad para seguir aprendiendo y profundizando en las herramientas que fuimos viendo. El código se encuentra en un repositorio de Github para que puedan descargarlo y hacer las pruebas ustedes mismos&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/akalautaro"&gt;
        akalautaro
      &lt;/a&gt; / &lt;a href="https://github.com/akalautaro/datos-con-python"&gt;
        datos-con-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;datos-con-python&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Repositorio para alojar la notebook que muestro en el siguiente post de dev.to &lt;a href="https://dev.to/akalautaro/aprende-a-programar-como-un-presidente-32c1" rel="nofollow"&gt;Aprende a programar como un presidente&lt;/a&gt;&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/akalautaro/datos-con-python"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;En mi perfil de Github pueden encontrar repositorios con proyectos personales y algunos challenges de data engineering principalmente&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://github.com/akalautaro" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--aH8Qb_z0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/55287162%3Fv%3D4%3Fs%3D400" height="460" class="m-0" width="460"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://github.com/akalautaro" rel="noopener noreferrer" class="c-link"&gt;
          akalautaro (Lautaro Celli) · GitHub
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          akalautaro has 21 repositories available. Follow their code on GitHub.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--GiYjWU4I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.githubassets.com/favicons/favicon.svg" width="32" height="32"&gt;
        github.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Ojalá se copen haciendo cosas con python 🤠&lt;/p&gt;

</description>
      <category>python</category>
      <category>pandas</category>
      <category>beginners</category>
      <category>webscraping</category>
    </item>
  </channel>
</rss>
