Video Summary and Transcription
La Charla discute sobre la plataforma web y la experiencia del orador con Remix. Cubre problemas con las mutaciones y la presentación de datos de formulario, la corrección de errores y el descubrimiento de características faltantes. El orador también habla sobre trabajar en JS DOM y estándares web, abrir una solicitud de extracción y hacer progresos, y trabajar en Chromium, Gecko y Firefox. La Charla concluye con discusiones sobre el tiempo hasta GA y la documentación, así como las contribuciones y conclusiones del orador.
1. Introducción a la Plataforma Web
Hola, mi nombre es John. Hoy, voy a hablar sobre la plataforma web y compartir una experiencia que cambió mi percepción. La plataforma web está abierta a todos, y te mostraré lo fácil que es involucrarse. El código vive en un espectro, desde aplicaciones hasta bibliotecas de código abierto. Esta experiencia ocurrió en un encuentro de remix, donde mostré aplicaciones construidas con remix. Desafortunadamente, la aplicación se rompió después de una actualización a la última versión de Remix. Vamos a discutir cómo Remix maneja las mutaciones.
Hola, mi nombre es John. Trabajo en Netflix, y hoy voy a hablar sobre la plataforma web. Entonces, un refrán común que escuchamos como desarrolladores web es que deberíamos usar la plataforma. Pero qué es la plataforma? ¿Quién decide qué va a entrar en ella? ¿Cómo deciden los implementadores de navegadores qué van a hacer y qué no van a hacer? ¿Podemos nosotros, como desarrolladores de UI, tener voz en cómo se ve eso? Y la respuesta es sí. Tú eres la plataforma. Esto es algo que está realmente abierto a todos. Y vamos a repasar una experiencia que tuve para mostrarte lo fácil que es involucrarse. Entonces, si pensamos en el código, el código vive en un espectro, ¿verdad? Tenemos nuestras aplicaciones, estamos escribiendo en el extremo izquierdo, tenemos cosas que usamos, como React, más o menos en el medio. Y luego tenemos la plataforma web, el DOM, HTML, ese tipo de cosas. No sé ustedes, pero para mí se sienten como algo que simplemente está ahí, ¿verdad? Es algo bueno en su mayoría. Ocasionalmente tienes que trabajar alrededor de algo extraño. Pero es simplemente el mundo en el que vivimos. Y entonces, si quisiéramos cambiar algo, podríamos verlo como una especie de gráfico como este. Puede ser muy intimidante pensar en cambiar cosas en el lado superior derecho. Se necesita mucha experiencia, mucho proceso. Mientras que las cosas en el lado izquierdo, eso es fácil, eso es cómodo. Hacemos eso todos los días. Y luego las bibliotecas de código abierto, frameworks, eso está más o menos en el medio. Pero esta experiencia que tuve durante el último año ha cambiado totalmente esta percepción para mí.
Entonces, hace aproximadamente un año estuve en un encuentro de remix. Entonces, remix, si no estás familiarizado, es un marco de trabajo completo para React que te permite construir aplicaciones web realmente geniales que funcionan muy bien. Estaba haciendo un trabajo en Netflix para apoyar esto internamente. Entonces, en el encuentro estaba mostrando algunas aplicaciones que construí alrededor de esto. Entonces, tengo una pequeña aplicación de tareas pendientes que escribí. La aplicación no es muy impresionante, pero muestra algunas características de remix como el mejoramiento progresivo y las interfaces de usuario optimistas, y está utilizando bibliotecas de componentes de Netflix y funcionando en infraestructura de Netflix. Y mientras la estaba mostrando, de manera vergonzosa, la aplicación estaba rota. Y la aplicación había funcionado antes. Entonces, esto es algo nuevo, algo había cambiado. Y lo que había sucedido fue que en realidad se actualizó a la última versión de Remix hace aproximadamente una semana. Entonces, antes yo
2. Mutaciones y Envío de Datos de Formulario
Normalmente, las mutaciones se modelan con formularios. El equipo de Remix solucionó un error pero introdujo otro. El proceso de envío de datos del formulario fue cambiado, causando problemas con el orden de serialización. En lugar de cambiar el formulario, escribí un componente grande y feo para mantener la funcionalidad deseada. Las bibliotecas y los frameworks son más accesibles en el espectro.
Antes de entrar en el error, quiero hablar de cómo Remix maneja las mutaciones. Entonces, normalmente, las mutaciones siempre se modelan con formularios. Por ejemplo, esta fila es un formulario que permite completar, actualizar o eliminar uno de tus elementos de la lista de tareas. Y entonces, hay un par de pequeños widgets aquí para alternar la finalización o eliminar cosas. Y cuando demostré la aplicación, esos dos widgets estaban rotos. Lo interesante es que debido al mejoramiento progresivo, puedes apagar JavaScript y en realidad todavía funcionaba correctamente. Así que solo estaba roto cuando JavaScript estaba activado. Y la razón es que el equipo de Remix había solucionado el error, pero en el proceso introdujo un error ligeramente diferente. Entonces, el proceso de envío de datos del formulario que tenían antes de esto, podría sobrescribir potencialmente otros inputs, ¿verdad? Entonces, si tú tenías un botón de enviar con un nombre, si tenías otro input con el mismo nombre, el botón de enviar simplemente sobrescribiría lo que tenías. Y entonces, lo solucionaron para decir, no, vamos a agregar lo que el botón de enviar tiene al final del formulario. Ahora, para la mayoría de los formularios, esto nunca importaría. Para mi formulario, en realidad sí lo hizo. Porque estaba confiando en el orden en que las cosas se serializaban en base a su orden en el DOM. Entonces, tenía un botón de enviar por defecto cuando pulsabas enter, el icono de finalización era en realidad un botón de enviar. Entonces, te darás cuenta de que tiene un nombre, tiene un valor, y eso establecerá el nombre y valor correctos para la finalización. Y el botón de eliminar también era un botón de enviar con un nombre y un valor. Y esos en realidad sobrescribirían otros valores que tenía más adelante en el formulario. Y entonces, porque ahora se serializaban en un orden diferente, en el lado del servidor, se estaba manejando incorrectamente. Ahora, tú sabes, la mayoría de la gente diría, está bien, lo que sea, solo ajustaré mi formulario, eso es todo, y seguir adelante. Pero yo no soy normal, ¿verdad? Y por eso estoy dando esta charla hoy. Pero, ya sabes, estaba mirando esto, y estoy pensando, sabes, esta regresión no se mantendrá. Tú sabes, esta regresión no se mantendrá, hombre. No quería cambiar mi formulario. No quería tener que hacer algo solo porque, ya sabes, ellos estaban equivocados, ¿verdad? Y entonces en lugar de eso, fui y escribí un componente grande y feo para no tener que hacerlo. ¿Verdad? Así que tengo algunas travesuras de input ocultas. De esa manera todavía puedo hacer que mis botones funcionen como yo quería. Esto es un poco asqueroso, pero me permitió mantener mi formulario como yo quería. Pero volviendo a nuestro espectro, ¿verdad? Como estoy operando en mi código aquí, pero como las bibliotecas y los frameworks, eso es un poco accesible. He hecho un poco de código abierto. Tal vez podría ayudar a las cosas en el territorio de Remix. Ya sabes, las bibliotecas, ¿verdad? Están bastante bajas en ese gráfico.
3. Arreglando un Error y Descubriendo Características Faltantes
Presenté un problema sobre un error en Remix. Intenté diferentes enfoques para solucionarlo, incluyendo la implementación de la construcción de datos de formulario por mí mismo y utilizando trucos de entrada ocultos. También descubrí una característica faltante en la especificación del navegador. Finalmente, los cambios se realizaron en React Router, pero encontré problemas con JS DOM.
Y lo primero que hice fue pensar, sabes, realmente debería presentar un problema. Así que al día siguiente fui y abrí un problema en el repositorio de Remix y dije, hey, aquí esto es un error, sabes, como, sería genial arreglar eso algún día. Y lo dejé así.
Pero pasaron un par de semanas y pensé, sabes, en realidad sería genial solucionar este error. Así que quiero devolver un poco, no parece un error fácil, ¿qué tan difícil podría ser, verdad. Resultó ser un poco complicado, verdad. Resulta que, sabes, los navegadores saben cómo construir un objeto de datos de formulario a partir de un formulario, pero no saben cómo especificar el remitente en la posición correcta. Así que para solucionar esto, pensé, OK, una opción sería que yo mismo podría implementar la construcción de datos de formulario. Así que miré la especificación y copié y pegué el texto de ella y luego la implementé, lo cual son como 300 líneas de código, lo cual es un poco mucho. Así que el segundo enfoque que tomé es como tal vez puedo hacer esos trucos de entrada ocultos, pero hacer eso en remix. Y eso fue mucho menos código. Pero de nuevo, es un poco chapucero. No sé si es el mejor enfoque, pero me siento un poco mejor ahora porque en realidad hace seis meses, Sebastian añadió básicamente lo mismo a React con el material de acción de formulario que añadieron. Así que no está mal. Estoy en buena compañía, pero no estaba completamente satisfecho con estos enfoques, pero quería iniciar una discusión con el equipo de Remix para ver si podíamos solucionarlo.
Y mientras hacía esta investigación, me di cuenta de que las personas inteligentes del navegador habían estado buscando en esto antes. Se dieron cuenta de que en realidad había una característica faltante en el navegador, en la especificación, en cuanto a cómo podría funcionar esto porque, como dije, los foros, los navegadores saben cómo enviarlos y saben cómo poner correctamente el botón de envío allí. Pero cuando estás construyendo un foro, un conjunto de datos de foro a partir de un foro, el objeto de datos de formulario no sabía cómo hacer eso. No había una forma de especificar el remitente. Y así que dieron algunas ideas sobre cómo podría ser eso, cuál es la mejor interfaz, pero realmente no había sucedido nada desde 2019. Y así que pensé, está bien, eso es bueno saber. Tal vez algún día pueda usar eso. Eso sería genial. Pero mientras tanto, tenía otro problema con mi PR.
Así que hice estos cambios, pero el equipo de Remix estaba en medio de refactorizar un montón de cosas y graduando esta funcionalidad de Remix a React Router, lo que significaba que no podía hacer esos cambios allí, y tendrían que aterrizar en React Router en alguna fecha futura cuando eso estuviera hecho. Así que lo dejé en un patrón de espera, y pasaron un par de meses y finalmente los cambios aterrizaron en React Router, y así que pude hacer esas PRs allí en lugar de en Remix. Pero entonces tuve un nuevo problema, ¿verdad? Así que React Router hace sus testing con Jest y JS DOM, y había algunas características faltantes, funcionalidad faltante en JS DOM. Así que si no has usado JS DOM, es una biblioteca realmente genial. Alimenta Jest, React testing library. Es principalmente autor y mantenido por Dominic, un tipo super inteligente, y pienso en él como un JS DOM, así que ahora tú también puedes.
4. Trabajando en JS DOM y Estándares Web
Trabajar en JS DOM fue una experiencia positiva. JSDOM es una gran implementación de un navegador en JavaScript. Aprendí sobre especificaciones y pensé en ayudar con los datos de formulario. Hablemos del Consorcio World Wide Web, el Grupo de Trabajo de Tecnología de Aplicaciones Hipertexto Web y las Pruebas de la Plataforma Web. Estos grupos impulsan los estándares web y tienen repositorios en GitHub.
Debo decir, sin embargo, que trabajar en JS DOM fue una de las experiencias más positivas que he tenido en código abierto. Así que Dominic fue super receptivo, super amable, super paciente con muchas cosas en las que estaba trabajando y mis preguntas, y así trabajar en JS DOM, el repositorio, fue fantástico, y lo recomiendo encarecidamente si tienes la oportunidad. Así que hice esos cambios, y hubo algunas otras cosas que aprendí sobre JS DOM en el camino.
Así que JSDOM, el repositorio, es una implementación realmente genial de un navegador en JavaScript. Así que lo que eso significa es que está siguiendo las mismas especificaciones, está probando exactamente de la misma manera, y está utilizando las mismas interfaces que los navegadores utilizan para generar sus JavaScript bindings. Así que eso fue interesante. Y aprendiendo sobre esto, me estoy familiarizando cada vez más con las especificaciones y el proceso de cómo funcionan estas cosas, y me hizo pensar, como, tal vez podría ayudar a ese formulario data a avanzar. La gente del navegador reconoce la necesidad, tal vez podemos reactivar esa discusión y algún día realmente usar eso. Pero de nuevo, como, especificaciones. Esto es super intimidante, super desalentador. ¿Cómo se hace eso? Como, eso está en la parte superior derecha del gráfico. No sé cómo. ¿Cómo funciona esto, verdad? Así que hablemos de algunos de los grupos.
Está el Consorcio World Wide Web. Han estado presentes desde el principio de los tiempos. Y si piensas en cosas como CSS o ARIA, están impulsando esas especificaciones y ayudando a mejorar la web mediante la construcción de estos standards. Y hay varias formas en las que puedes involucrarte, así que te sugiero seguir estos enlaces, revisar su GitHub, puedes comentar sobre los borradores y cosas así. Otro grupo es el Grupo de Trabajo de Tecnología de Aplicaciones Hipertexto Web. Así que este grupo fue formado por vendedores de navegadores y otras personas interesadas, en un esfuerzo por avanzar en la web de una manera más pragmática, una manera pragmática en contacto con lo que necesitan los desarrolladores web. Y si piensas en las cosas fundamentales que usamos, como el DOM HTML, estos son todos los flujos de trabajo impulsados por este grupo. Y también están en GitHub, y así cada una de estas especificaciones es en realidad un repositorio de GitHub, lo cual es interesante. Además, hay otro repositorio para revisar llamado Pruebas de la Plataforma Web. Esto es realmente genial. Así que toda la plataforma web se prueba a través de las pruebas de la plataforma web. Y lo que es realmente genial es que este es un repositorio que es compartido por todas las implementaciones. Así que empujan y tiran en todas las direcciones. Así que si una nueva característica aterriza, tendrá pruebas aquí que los navegadores luego utilizan como parte de su suite de pruebas. Así que volví a esta discusión, y me di cuenta de que no era sólo una discusión, era un problema de GitHub en el repositorio XHR. Y esto se ve cada vez más familiar. Es un repositorio de GitHub.
5. Abriendo un Pull Request y Progresando
Abrí un pull request para agregar Submitter a los datos del formulario y cambiar el texto de la especificación. También enlacé a otro PR para las pruebas de la plataforma web. A la mañana siguiente, recibí una respuesta afirmativa de Aravin Kestra y el editor de la especificación XHR. Los navegadores impulsan la especificación, y obtener su aprobación puede ser desalentador. Incluso si obtienes su aprobación, hacer que esté en su hoja de ruta lleva tiempo. Para ayudar al proceso, construí un POC en JS DOM, pero hacerlo en Chromium es un desafío.
Y veo que tienen una guía de contribución y pull requests e issues y cosas así. Y entonces pensé, tal vez podría abrir un pull request. No sé qué implica y cuán difícil va a ser y podría tener muchas reuniones y llevar mucho tiempo. Pero déjame intentarlo, ¿qué es lo peor que podría pasar? Así que abro un pull request. Y hay dos cosas que hice en este PR. Así que quería agregar Submitter a los datos del formulario. Entonces lo primero es definir la interfaz. ¿Cómo se ve eso? Así que fui con una de las propuestas en ese issue de XHR que había visto antes, parecía buena. Y lo añadí a la interfaz que utilizan los navegadores para generar sus enlaces de JavaScript. Y luego la otra parte del PR es cambiar el texto de la especificación para que un implementador o un desarrollador web sepa exactamente cómo podría funcionar y cómo debería funcionar de manera consistente en todos los navegadores. Y luego lo otro que hay que hacer en este PR es enlazar a otro PR para las pruebas de la plataforma web. Y entonces abrí uno de esos y añadí un montón de pruebas que parecían así para probar mi nueva funcionalidad de datos de formulario que quería en un navegador. Así que esto es sólo un ejemplo, pero se parece mucho a otras pruebas que podríamos escribir en otros frameworks de pruebas en JavaScript. Así que abrí esos PRs y me fui a la cama. Y me sorprendió a la mañana siguiente ver una respuesta afirmativa de Aravin Kestra y el editor de la especificación XHR, no sólo respondiendo afirmativamente, sino también pagando a los implementadores de los tres principales navegadores. Y nunca, como, en un millón de años lo habría esperado. Así que fue super genial ver cuán comprometidos y cuán involucrados están y cuán útiles son estas personas para avanzar en la web. Pero entonces, ya sabes, lo que pasa es que, no me di cuenta de que los navegadores en su mayoría impulsan la especificación, no al revés. Así que para hacer un cambio, tienes que obtener la aprobación de los navegadores. Y eso está aquí arriba a la derecha también. Eso es desalentador. Y luego, incluso si obtienes la aprobación, ¿cómo lo pones en su hoja de ruta para cambiar? Como, esto parece que va a llevar un tiempo. Y entonces mi par de especificaciones estaba languideciendo por un tiempo, y, ya sabes, no quiero ser esa persona y como pingearlos y decir, hey, ¿pueden mirar esto? ¿Qué piensan, deberíamos hacerlo o no? Porque ellos tienen trabajos de día. Yo tengo un trabajo de día. Esto es como un, ya sabes, esto es una cosa de noches y fines de semana. Pero pensé que tal vez podría ayudar al proceso. Tal vez podría construir un POC. Y así lo hice en JS DOM, y eso fue bastante sencillo. Pero pensé, ¿podría realmente hacer esto en Chromium o algo así? Y no tengo idea de lo que estoy haciendo. Quiero decir, seamos honestos aquí.
6. Trabajando en Chromium, Gecko y Firefox
Como desarrollador de interfaz de usuario, exploré Chromium y Gecko, encontrando su documentación para desarrolladores y el proceso de incorporación fácil de navegar. Publiqué en el PR de la especificación, recibí respuestas afirmativas y realicé cambios en la especificación. Para hacer cambios en los propios navegadores, tomé POCs y los implementé, abriendo y fusionando diferentes PRs. Algunas conclusiones: Chromium utiliza Gerrit para la revisión de código, tiene buenos documentos para desarrolladores y tarda unos dos meses en aparecer los cambios. Firefox utiliza Fabricator y tiene un proceso más ligero.
Soy un desarrollador de interfaz de usuario, no sé, C++, sí, he hecho algo en el pasado, pero no, como, sí, por favor no. Pero fui y miré los documentos de Chromium. Miré todos estos grandes recursos que tienen, y descubrí que en unos tres comandos podría tener una compilación de Chromium funcionando localmente. Y aunque tardó un poco en la construcción inicial, lo que luego descubrí es que podía hacer reconstrucciones en menos de un minuto. Y eso me dio la confianza para empezar a iterar.
Y así, durante el transcurso de un fin de semana, pude implementarlo realmente en Chromium. Y basado en esta experiencia positiva con cómo funcionan sus documentos para desarrolladores y lo fácil que es incorporarse, fui y miré Gecko. Y en ese mismo fin de semana, pude hacerlo funcionar en Firefox. Y de nuevo, proceso similar allí, super fácil de empezar, gran documentation para desarrolladores. Así que basado en eso, pensé, genial, déjame publicar algo en el PR de la especificación. Añadí las capturas de pantalla y marqué a los implementadores y todos respondieron afirmativamente. Como, sí, esto es genial. Hagamos este cambio en la especificación.
Así que conseguimos hacer el cambio en la especificación, pero luego lo siguiente es como, ¿cómo hacemos realmente el cambio en los propios navegadores? ¿Cómo nos involucramos en ese proceso? Y de nuevo, es como, esto es algo que me importa mucho. Quiero decir, los navegadores están interesados en hacerlo, pero no quiero ser molesto. Y así pensé que tal vez podría implementarlo yo mismo. Así que profundizando en su documentation para desarrolladores y procesos, descubrí que era bastante fácil tomar esos POCs e implementarlos. Y así conseguí abrir diferentes PRs y fusionarlos en el transcurso de una o dos semanas.
Así que aquí hay algunas conclusiones que aprendí trabajando en los tres navegadores. Así que Chromium, aquí están los puntos rápidos. Utilizan Gerrit para la revisión de código. El CodeBase es C++. Tienen muy buenos documentos para desarrolladores. Sólo léelos detenidamente. Todas las testing son con pruebas de plataforma web. El proceso es un poco complicado para hacer un cambio, pero no está mal. Y así, desde el momento en que aterrizas un cambio hasta que aparece en el Chromebook de tu hijo, estás mirando unos dos meses. Firefox, se siente bastante similar. Están usando Fabricator. El proceso es un poco más ligero.
7. Tiempo hasta la masterclass y Documentación
El tiempo real desde la fusión hasta la masterclass en tu portátil Linux es de unas cinco semanas. Safari es mi navegador favorito, y están en GitHub, lo que hace el proceso más cómodo. Sin embargo, el tiempo hasta la masterclass es incierto debido a los ciclos de lanzamiento de Apple. La documentación es esencial para dar a conocer y utilizar los cambios. MDN y el repositorio de datos de compatibilidad del navegador en GitHub proporcionan una gran herramienta y documentación para empezar.
Y así, el tiempo real desde la fusión hasta la masterclass en tu portátil Linux, es como de cinco semanas o así. Y en realidad mi favorito fue Safari. Están en GitHub. Así que eso me resultó un poco más cómodo. A lo que estoy acostumbrado. Y el proceso es muy ligero. Lo único que destacaría aquí es el tiempo hasta la masterclass, es una especie de desconocido. Con Apple siendo una caja negra y sus ciclos de lanzamiento y ese tipo de cosas. Así que realmente no sabes cuándo va a aparecer en el iPad de la abuela, pero eventualmente saldrá. Así que hice esos cambios y hombre, estamos avanzando a buen ritmo. Esto es emocionante. Me di cuenta, sin embargo, de que la otra gran cosa es que tenemos que documentar esto porque nadie sabe de ello o sabe cómo usarlo. ¿Cuál es el punto, verdad? Así que la documentation, esto parece un poco intimidante, pero estamos avanzando, vamos a averiguarlo. Y resulta que MDN, también está en GitHub. Tienen una gran tooling y documentation para empezar. Así que echa un vistazo al repositorio de contenido. Puedes descargar MDN y ejecutarlo localmente. Otro repositorio a tener en cuenta es el de los data de compatibilidad del navegador. Así que eso se alimenta de esas tablas de compatibilidad en MDN y puedo usarlo. Así que fui y abrí aquí para esos.
8. Contribuciones y Conclusiones
Obtuve cosas en MDN, vi las columnas volverse verdes a medida que los cambios se implementaban. Descubrí un problema en JSDOM, lo solucioné. Actualicé React Router. Implementé una solución más sencilla. Conclusiones: impresionado con las personas involucradas, los procesos simplificados facilitan la participación, cualquiera puede contribuir.
Y así, sí, obtuve algunas cosas en MDN y conseguí que mi tabla de compatibilidad funcionara. Y fue realmente divertido ver cómo durante el transcurso de un mes o dos esas columnas se volvían verdes para el remitente a medida que las cosas se implementaban, ya sabes, pasaron de ser experimentales a ser lanzadas.
Ahora, mientras todo esto sucedía, descubrí que había un problema en JSDOM. Había causado algunos problemas, tuve que solucionarlos. También necesitaba actualizar React Router para usar el último Jest en JSDOM, así que tuve que hacerlo. Pero en total, para cuando todo esto terminó, ahora estábamos en un punto donde estos cambios para el remitente estaban en todos los principales navegadores, las últimas versiones. Y así pude implementar una solución mucho más sencilla para React Router.
Lo que terminé haciendo es simplemente usar un remitente si está allí. Y si no, si es un navegador más antiguo, entonces seguimos adelante y añadimos la entrada del remitente al final. Lo cual está bien el 99.9% del tiempo. Para cualquiera que le importe, en realidad tengo un polyfill que puedes hacer que funcione correctamente en todos los navegadores. Pero de nuevo, probablemente hay como dos personas en el mundo a las que les importa eso. Pero sí, es muy genial.
Así que supongo que algunas conclusiones. Puedes estar mirando esto como el Dr. Malcolm sacudiendo la cabeza, solo porque puedes no significa que debas, ¿verdad? Pero honestamente no me importa. Este fue un gran proceso. Y quedé impresionado en cada paso del camino con las personas con las que trabajé, ya sabes, desde los autores y mantenedores de la biblioteca hasta los planificadores del navegador y los editores de especificaciones. Todos fueron muy amables, muy serviciales y muy acogedores. Y los procesos que han creado son extremadamente eficientes y facilitan mucho la participación de cualquiera. Así que, ya sabes, ya sea un pequeño error que quieras solucionar, tienes una idea para, ya sabes, mejorar los documentos de MDN, lo que sea, ya sabes, este gráfico está totalmente equivocado, ¿verdad? De nuevo, sé que tu experiencia puede variar de la mía, pero solo por lo que vi durante el último año, lo redibujaría así. Es un gráfico mucho más plano, ese pequeño bache en el medio no está destinado a lanzar sombras, es solo, ya sabes, es más para mostrar lo geniales que son las cosas en el lado derecho y el gran trabajo que han hecho. Y así, ya sabes, sé que no soy la persona equivocada, ya sabes, todo el mundo me lo dice y está bien. Pero también soy poco destacado, ¿verdad? Como esto no es ciencia espacial lo que estaba haciendo, esto está muy bien documentado y han facilitado mucho la participación. Así que si yo puedo hacerlo, tú también puedes. Gracias.
Comments