Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fearless refactors con AST

33ca55590f4de37e4b1dbb80d5576295?s=47 Sanguino
December 10, 2019

Fearless refactors con AST

Enfréntate a breaking changes y refactors sin miedo. AST (Abstract Syntax Trees) es utilizado por muchos compiladores para parsear el código antes del análisis léxico.

En este meetup queremos mostrar cómo podemos usar el potencial de AST para parsear nuestro código para hacer cambios masivos en nuestro código fuente, sin tener que tratar con las lineas de codigo directamente.

Constará de una parte de explicación de que es AST, donde se usa, codemods, jscodeshift, ejemplos de uso real y una demo de cómo refactorizamos miles de ficheros de un proyecto en pocos minutos.

Comienza a codificar tus refactors!

33ca55590f4de37e4b1dbb80d5576295?s=128

Sanguino

December 10, 2019
Tweet

Transcript

  1. Fearless refactors con AST Pablo Ingold, Miguel G. Sanguino Empieza

    a codificar tus refactors! 10/12/2019
  2. Técnicas de refactor 1. Find-and-replace (en un directorio completo) para

    modificar ficheros de código.
  3. 1. Find-and-replace (en un directorio completo) para modificar ficheros de

    código. Técnicas de refactor
  4. 1. Find-and-replace (en un directorio completo) para modificar ficheros de

    código. 2. Script con expresiones regulares usando grupos de captura. Técnicas de refactor
  5. 1. Find-and-replace (en un directorio completo) para modificar ficheros de

    código. 2. Script con expresiones regulares usando grupos de captura. Técnicas de refactor
  6. 1. Find-and-replace (en un directorio completo) para modificar ficheros de

    código. 2. Script con expresiones regulares usando grupos de captura. Aquí es donde entran los “codemods” y AST Técnicas de refactor
  7. Codemods

  8. “Código que modifica código” Se suelen usar para: • Actualizar

    código Fuente manteniendo el “coding style” y convenciones. • Hacer cambios en nuestro código cuando se modifica un API. • Auto-fix del código fuente cuando un paquete público introduce breaking changes. Codemods
  9. Qué es AST?

  10. Abstract syntax tree An abstract syntax tree is a tree

    representation of the abstract syntactic structure of source code written in a programming language. The syntax is "abstract" in the sense that it does not represent every detail appearing in the real syntax, but rather just the structural or content- related details. - Wikipedia “ “
  11. • Abstract Syntax Trees son estructuras de datos muy utilizadas

    en compiladores, generalmente como resultado de la fase de análisis de sintaxis. • AST se usa intensamente durante el análisis semántico, donde el compilador verifica el uso correcto de los elementos del programa y el lenguaje. • Frente al código fuente, AST no incluye signos de puntuación y delimitadores no esenciales (llaves, punto y coma, paréntesis, etc.). Abstract syntax tree
  12. Cada nodo del árbol representa una parte del código fuente.

    Cómo AST parsea el código Lo que escribes Nodos AST Const var name ‘=‘ value ‘;’ Identifier Literal VariableDeclaration
  13. Qué pinta tiene un arbol AST Const var name ‘=‘

    value ‘;’ Identifier Literal VariableDeclaration
  14. Consideremos estos 4 ejemplos: Por qué AST y no Regex

    Todos generan el mismo árbol AST
  15. AST

  16. AST

  17. AST

  18. AST

  19. AST

  20. AST

  21. AST

  22. AST

  23. AST

  24. AST

  25. AST

  26. AST

  27. AST

  28. AST

  29. AST

  30. AST

  31. AST

  32. AST

  33. AST

  34. AST

  35. AST

  36. AST

  37. AST

  38. AST

  39. Todos estos proyectos usan AST y puede que no lo

    supierais AST en JavaScript
  40. Las reglas de Eslint están escritas con AST para analizar

    tu código AST en JavaScript
  41. V8 usa Ignition para parsear javascript en AST y compilarlo

    en bytecode AST en JavaScript https://v8.dev/blog/background-compilation
  42. Babel parsea tu código a AST, hace transformaciones al árbol

    e imprime el código de vuelta. AST en JavaScript
  43. AST codemods

  44. AST codemods Vamos a usar codemods para parsear nuestro código

    a AST, hacer transformaciones en el árbol sintáctico y volver a imprimir nuestro código al fichero original sin perder el “code style”
  45. Python: https://pybowler.io/ Java: https://www.vogella.com/tutorials/EclipseJDT/article.html#using-jdt-to-modify-existing-source-code CSS: https://postcss.org/ C++ & C#: https://www.jetbrains.com/resharper-cpp/

    SQL: https://www.red-gate.com/products/sql-development/sql-prompt/ Javascript: https://github.com/facebook/jscodeshift AST codemod libraries
  46. jscodeshift

  47. We have tens of thousands of JavaScript modules at Facebook.

    When an engineer makes breaking API changes we transform all of our JavaScript to new code. To deprecate and remove legacy APIs Felix Kling and I developed a tool called jscodeshift for doing AST-to-AST transforms for JavaScript. - Christoph Nakazawa jscodeshift “ “
  48. jscodeshift es un Toolbox. • Utiliza el parser de babel

    (babylon), ast-types (libreria de Ben Newman) para crear nodos y recast para el “pretty-printing”. • Es un wrapper de éstas 3 herramientas que nos prove de un API para poder hacer find, filter, map y replace de los nodos de AST. • También nos proporciona un runner/worker para poder transformer miles de ficheros en paralelo. Si no habeis trabajado nunca con AST podeis usar AST Explorer desarrollado por Felix para inspeccionar los nodos AST. jscodeshift
  49. Vocabulario: Nodes: Son la unidad minima del AST, Tambien llamados

    “AST nodes.” Son objetos simples y no nos proven de ningún método. Node-paths: Wrappers al rededor de los nodos AST que nos da la libreria “ast-types” para poder recorrer el AST. Los nodos por si solos no tienen información del parent o su scope, los node-paths nos dan esa información. Collections: Grupos de cero o más node-paths que nos devuelve el API de jscodeshift cuando hacemos queries soble el AST. Collections contienen Node-paths, Node-paths contienen Nodes, Y los Nodes son de lo que está hecho AST jscodeshift
  50. Usamos Babel y Eslint en el día a día así

    que tenia sentido elegir uno de estos para nuestros codemods. Eslint lo descartamos antes de empezar, esta pensado para otro tipo de tareas, no imprime de vuelta del AST a código. Pusimos a Babel y jscodeshift a trabajar para saber cual era mejor para lo que queríamos: • Babel transforma código que va a ser ejecutado en un navegador, le da igual el código que genera. Añadimos recast para parsear el código y mantener el “code style”. • Las colecciones de jscodeshift nos permitían recorrer el árbol con más facilidad y con menos código. • Los codemods con Babel se veían más imperativos, con jscodeshift eran más declarativos. Jscodeshift trae todo lo que necesitabamos “out of the box”, nos da herramientas que hacen que nuestros codemods sean más pequeños, más legibles, más reutilizables y eramos más rápidos desarrollandolos. Porqué elegimos jscodeshift sobre Babel o Eslint
  51. js-codemod/template-literals: Casos de uso simples El repo de js-codemod contiene

    una colección de scripts que podemos utilizar. js-codemod script
  52. js-codemod/object-shorthand : Casos de uso simples El repo de js-codemod

    contiene una colección de scripts que podemos utilizar. js-codemod script
  53. Breaking changes

  54. En ING tenemos proyecto con lit-element. Tenemos un catalogo de

    componentes compartido llamado ing-web Hace unos meses, ing-icon introdujo un breaking change para evitar posibles ataques xss: Enfrentandose a breaking changes
  55. Imaginemos que tenemos un proyecto con multiples usos de ing-icon.

    Quieres actualizar la versión de ing-web, pero para eso hay que actualizar todos los atributos .svg antes. Enfrentandose a breaking changes
  56. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes
  57. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes Executamos jscodeshift sobre el código fuente y nos devuelve una colección de nodos Importamos el fichero de código y el api de jscodeshift
  58. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes Devuelve una colección con todos los tag templates cuyo tag es html y tiene un template literal como argumento
  59. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes Buscamos los literals
  60. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes Filtramos la colección y nos quedamos solo con los que sean tags <svg>
  61. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes Con esto hemos identificado todos los nodos que queremos reemplazar
  62. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes Creamos un template literal con el contenido del string con <svg> original
  63. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes Creamos un tag template con el tag ‘tag’ y le pasamos el template literal como argumento
  64. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes Creamos un arrow function con el parámetro ‘tag’ y el tag template recién creado como body de la función
  65. Hemos escrito este codemod para que haga todo el trabajo

    por nosotros Enfrentandose a breaking changes 65 Ejecutamos replaceWith sobre todos los nodos que encontramos pasándole el arrow function recién creado
  66. Enfrentandose a breaking changes Por útimo convertimos AST en código

    de nuevo Hemos escrito este codemod para que haga todo el trabajo por nosotros
  67. Enfrentandose a breaking changes Fichero original jscodeshift codemod Resultado

  68. Enfrentandose a breaking changes Y eso es todo, hemos adaptado

    todos nuestros ficheros a un breaking change. Todo lo que hay que hacer es escribir un pequeño script!!
  69. Y eso es todo, hemos adaptado todos nuestros ficheros a

    un breaking change. Todo lo que hay que hacer es escribir un pequeño script!! Enfrentandose a breaking changes
  70. Manteniendo código legacy

  71. Manteniendo código legacy 2.048 Paquetes Frontend { } 1.947.006 Líneas

    de código {*.js} 1.436.705 Líneas de javascript Estado actual de las aplicaciones frontend en ING España *node_modules excluido.
  72. Manteniendo código legacy 2.048 Paquetes Frontend { } 1.947.006 Líneas

    de código {*.js} 1.436.705 Líneas de javascript 100 Paquetes Libraries Estado actual de las aplicaciones frontend en ING España { } 199.964 Líneas de código {*.js} 197.146 Líneas de javascript *node_modules excluido.
  73. Manteniendo código legacy 2.048 Paquetes Frontend { } 1.947.006 Líneas

    de código {*.js} 1.436.705 Líneas de javascript 100 Paquetes Libraries Estado actual de las aplicaciones frontend en ING España Node y Build tasks 91 Paquetes { } 199.964 Líneas de código { } 340.982 Líneas de código {*.js} 197.146 Líneas de javascript {*.js} 126.923 Líneas de javascript *node_modules excluido.
  74. Manteniendo código legacy Estado actual de las aplicaciones frontend en

    ING España Core V1 V1 V1 V1 App dependencies V1
  75. Manteniendo código legacy Estado actual de las aplicaciones frontend en

    ING España Core V2 V1 V2 V1 V2 V1 V1 V1 V1 Legacy App dependencies V1 V2
  76. Manteniendo código legacy Estado actual de las aplicaciones frontend en

    ING España Core App dependencies V3 V2 V1 V3 V2 V1 V2 V1 V1 V1 V1 Legacy V1 V2 V3 V2 V1 V2 V1 V2 Legacy V3 V3
  77. Manteniendo código legacy Estado actual de las aplicaciones frontend en

    ING España Core V1 V1 V1 V1 App dependencies V1 V2 V3 V4 V2 V1 V2 V1 V2 Legacy V3 V2 V1 V3 V2 V1 V2 Legacy V3 V3
  78. Manteniendo código legacy Estado actual de las aplicaciones frontend en

    ING España Core V1 V1 V1 V1 codemod codemod codemod App dependencies V1 V2 V3 V4 V2 V1 V2 V1 V2 Legacy V3 V2 V1 V3 V2 V1 V2 Legacy V3 V3
  79. Manteniendo código legacy V1 Estado actual de las aplicaciones frontend

    en ING España V2 V3 V4 V4 V4 V4 V4 Core V4 V4 V4 V4 V4 V4 V1 V1 V1 V1 codemod codemod codemod No more legacy App dependencies V2 V1 V2 V1 V2 Legacy V3 V2 V1 V3 V2 V1 V2 Legacy V3 V3
  80. Manteniendo código legacy Ejemplo: uso de i18n Old way New

    way
  81. Manteniendo código legacy Old way Ejemplo: uso de i18n New

    way
  82. None
  83. Links útiles Articles • https://medium.com/@cpojer/effective-javascript-codemods-5a6686bb46fb • https://nec.is/writing/transform-your-codebase-using-codemods/ • https://www.toptal.com/javascript/write-code-to-rewrite-your-code/ •

    https://itnext.io/ast-for-javascript-developers-3e79aeb08343/ Tools • https://astexplorer.net/ • https://resources.jointjs.com/demos/rappid/apps/Ast/index.html
  84. Gracias @sanguinoide linkedin.com/in/sanguinoide linkedin.com/in/pablo-ingold