Slide 1

Slide 1 text

Fearless refactors con AST Pablo Ingold, Miguel G. Sanguino Empieza a codificar tus refactors! 10/12/2019

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Codemods

Slide 8

Slide 8 text

“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

Slide 9

Slide 9 text

Qué es AST?

Slide 10

Slide 10 text

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 “ “

Slide 11

Slide 11 text

• 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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Qué pinta tiene un arbol AST Const var name ‘=‘ value ‘;’ Identifier Literal VariableDeclaration

Slide 14

Slide 14 text

Consideremos estos 4 ejemplos: Por qué AST y no Regex Todos generan el mismo árbol AST

Slide 15

Slide 15 text

AST

Slide 16

Slide 16 text

AST

Slide 17

Slide 17 text

AST

Slide 18

Slide 18 text

AST

Slide 19

Slide 19 text

AST

Slide 20

Slide 20 text

AST

Slide 21

Slide 21 text

AST

Slide 22

Slide 22 text

AST

Slide 23

Slide 23 text

AST

Slide 24

Slide 24 text

AST

Slide 25

Slide 25 text

AST

Slide 26

Slide 26 text

AST

Slide 27

Slide 27 text

AST

Slide 28

Slide 28 text

AST

Slide 29

Slide 29 text

AST

Slide 30

Slide 30 text

AST

Slide 31

Slide 31 text

AST

Slide 32

Slide 32 text

AST

Slide 33

Slide 33 text

AST

Slide 34

Slide 34 text

AST

Slide 35

Slide 35 text

AST

Slide 36

Slide 36 text

AST

Slide 37

Slide 37 text

AST

Slide 38

Slide 38 text

AST

Slide 39

Slide 39 text

Todos estos proyectos usan AST y puede que no lo supierais AST en JavaScript

Slide 40

Slide 40 text

Las reglas de Eslint están escritas con AST para analizar tu código AST en JavaScript

Slide 41

Slide 41 text

V8 usa Ignition para parsear javascript en AST y compilarlo en bytecode AST en JavaScript https://v8.dev/blog/background-compilation

Slide 42

Slide 42 text

Babel parsea tu código a AST, hace transformaciones al árbol e imprime el código de vuelta. AST en JavaScript

Slide 43

Slide 43 text

AST codemods

Slide 44

Slide 44 text

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”

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

jscodeshift

Slide 47

Slide 47 text

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 “ “

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

Breaking changes

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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 original

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

Enfrentandose a breaking changes Fichero original jscodeshift codemod Resultado

Slide 68

Slide 68 text

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!!

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

Manteniendo código legacy

Slide 71

Slide 71 text

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.

Slide 72

Slide 72 text

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.

Slide 73

Slide 73 text

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.

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

Gracias @sanguinoide linkedin.com/in/sanguinoide linkedin.com/in/pablo-ingold