Problemas difíciles de GraphQL en Shopify

Rate this content
Bookmark

En Shopify a gran escala, resolvemos algunos problemas bastante difíciles. En este masterclass, cinco oradores diferentes describirán algunos de los desafíos que hemos enfrentado y cómo los hemos superado.

Tabla de contenidos:
1 - El infame problema "N+1": Jonathan Baker - Vamos a hablar sobre qué es, por qué es un problema y cómo Shopify lo maneja a gran escala en varios APIs de GraphQL.
2 - Contextualizando APIs de GraphQL: Alex Ackerman - Cómo y por qué decidimos usar directivas. Compartiré qué son las directivas, qué directivas están disponibles de forma predeterminada y cómo crear directivas personalizadas.
3 - Consultas de GraphQL más rápidas para clientes móviles: Theo Ben Hassen - A medida que tu aplicación móvil crece, también lo harán tus consultas de GraphQL. En esta charla, repasaré diversas estrategias para hacer que tus consultas sean más rápidas y efectivas.
4 - Construyendo el producto del futuro hoy: Greg MacWilliam - Cómo Shopify adopta las características futuras en el código actual.
5 - Gestión efectiva de APIs grandes: Rebecca Friedman - Tenemos miles de desarrolladores en Shopify. Veamos cómo estamos asegurando la calidad y consistencia de nuestras APIs de GraphQL con tantos colaboradores.

164 min
01 Dec, 2021

Comments

Sign in or register to post your comment.

Video Summary and Transcription

El masterclass cubrió varios temas relacionados con GraphQL en Shopify, incluyendo el problema Nplusone, carga en lote con resolutores perezosos, contextualización de APIs de GraphQL con directivas, optimización de GraphQL para dispositivos móviles, gestión de APIs de GraphQL grandes y manejo de campos y nulabilidad obsoletos. Los oradores compartieron ideas y soluciones a estos desafíos, como el uso de Active Record Preloading, la biblioteca GraphQL Batch y directivas personalizadas. También discutieron la importancia de medir el rendimiento, el diseño de paginación y las consultas paralelas para la optimización móvil. En general, el masterclass proporcionó información valiosa sobre cómo mejorar el rendimiento de GraphQL, el diseño de APIs y las estrategias de versionado.

Available in English

1. Introducción al Masterclass

Short description:

Gracias a todos por unirse a nosotros en el masterclass. Durante las próximas tres horas, cinco oradores diferentes discutirán los problemas que han abordado con GraphQL en Shopify. Cada sesión tendrá una duración de 20 minutos, seguida de un breve descanso y una sesión de preguntas y respuestas de una hora. Siéntanse libres de hacer preguntas en el chat durante todo el masterclass.

Entonces, una vez más, gracias a todos los que han podido unirse a nosotros aquí. Aprecio sinceramente su tiempo. Todos nosotros, todos nuestros oradores, todos en Shopify. Muchas gracias por estar allí y unirse a nosotros en el masterclass.

Así es como se verán las próximas tres horas. Será un poco diferente a lo que estamos acostumbrados, pero espero que sea un cambio positivo. Espero que también puedan compartir sus comentarios con nosotros al final de esto, pero vamos a tener cinco sesiones diferentes con cinco oradores diferentes. Todos ellos son ingenieros aquí en Shopify. Y todas estas sesiones hablarán sobre los problemas que hemos tenido que abordar con GraphQL aquí en Shopify. Esperamos que eso arroje algo de luz y obtengan una idea de cómo los equipos pudieron analizar los problemas y las diferentes metodologías que utilizaron para abordar el problema.

Cada sesión o charla tendrá una duración de 20 minutos. Y al final de eso, tendremos un descanso, un descanso corto de 10 minutos y luego tendremos una hora de horario de oficina, o una sesión de correo, si así lo desean. Entonces, si tienen preguntas, simplemente sigan haciéndolas aquí en el chat, nos aseguraremos de tomar nota de ellas. Y al final de eso, durante la última hora durante el horario de oficina, vamos a responder sus preguntas. Pero también, si tienen una pregunta muy específica sobre alguna de las sesiones a medida que se desarrollan, están pregrabadas, pero nuestros oradores están aquí en vivo, definitivamente pueden hacer sus preguntas en el chat, y ellos se encargarán de eso. Así que espero que esté bien. Suena bien y tiene sentido.

2. Introducción a la sesión de Jonathan

Short description:

Nuestra primera sesión es de Jonathan, un desarrollador de personal en Shopify, enfocándose en aplicaciones de escaparate para clientes. Jonathan está aquí para aclarar cualquier pregunta durante la sesión pregrabada. ¡Comencemos!

Entonces, sin más preámbulos, creo que nuestra primera sesión es de Jonathan. Jonathan está aquí. Jonathan, no sé si quieres tomarte un momento para saludar a las personas que se están uniendo antes de comenzar la sesión. ¡Hola a todos! Soy Jonathan, como verán en la charla, soy un desarrollador de personal aquí en Shopify, enfocándome en nuestras aplicaciones de escaparate para clientes. Desde el punto de vista de GraphQL, se trata de la API de escaparate, que es una de nuestras dos API públicas de GraphQL. Bienvenidos.

Fantástico. Cuéntanos algo sobre ti que probablemente no sepamos, déjame acercarlo más a casa, ¿cuál es tu lectura favorita actual o tu blog o boletín favorito en este momento? El blog de ingeniería de Shopify. Muy bien, muchas gracias, Jonathan. Jonathan es nuestro primer orador, como mencioné, todas nuestras sesiones están pregrabadas, pero siéntanse libres de hacer sus preguntas mientras se desarrolla la sesión. Jonathan está aquí para ayudar a aclarar cualquier cosa en caso de que sea necesario. Así que déjenme ver. Voy a compartir mi pantalla aquí, también compartiré el sonido. Muy bien, fantástico. Déjenme ver. Denme un pulgar hacia arriba si pueden escuchar el sonido aquí.

3. Jonathan Baker sobre el problema Nplusone

Short description:

Hola a todos. Mi nombre es Jonathan Baker, soy un desarrollador de personal aquí en Shopify y me he enfocado en características para construir escaparates personalizados como la API de escaparate. Hoy hablaré sobre una de las preocupaciones más comunes relacionadas con el rendimiento que cualquier API impulsada por GraphQL eventualmente encontrará, el infame problema Nplusone. GraphQL en Shopify comenzó en 2015 cuando tuvimos nuestro primer commit relacionado. Desde entonces, hemos acumulado más de seis esquemas de GraphQL para API internas y externas. Esos esquemas están compuestos por más de 5,000 tipos y mutaciones, y más de 1.7 millones de escaparates de comerciantes y 60,000 aplicaciones de socios son impulsadas por ellos. En total, nuestros puntos finales de GraphQL manejan un promedio de un millón de consultas por minuto. Puedes ver que GraphQL es muy importante en Shopify y nos hemos involucrado mucho en ello. Ese es el problema Nplusone. ¿Qué es? En pocas palabras, es lo que sucede cuando necesitas presentar una lista de objetos y cada objeto tiene un atributo almacenado en otro modelo. Estos suelen ser completamente separados del modelo principal y en una base de datos diferente. Veamos un ejemplo de esquema y veamos cómo estos problemas pueden manifestarse fácilmente. Entonces, ¿cómo lo solucionamos? Bueno, Rails tiene otro truco bajo la manga llamado Active Record Preloading. Al agregar otro modificador al final de nuestra consulta de artículo, Rails cargará automáticamente todos los autores únicos relacionados con el conjunto de resultados. Y como sabe de antemano quiénes son esos autores, puede hacerlo de manera eficiente en solo una consulta. Ahora, hay otra diferencia en los registros más allá del número de consultas SQL, el tiempo de respuesta. Puede que estés pensando que ocho milisegundos no parece una gran diferencia. Sin embargo, para ponerlo en perspectiva, supongamos que nuestro punto final de GraphQL no es multiproceso. Solo puede manejar una solicitud a la vez. Esto es bastante común. Esos 8 milisegundos son la diferencia entre manejar 4,600 solicitudes por minuto y más de 12,000 solicitudes por minuto. Eso es muy importante. Bueno, ¿qué sucede cuando hacemos una consulta en la que no nos importa el autor? Hm, eso es extraño. Aún estamos solicitando autores aunque no los estemos usando.

Hola a todos. Mi nombre es Jonathan Baker, soy un desarrollador de personal aquí en Shopify y me he enfocado en características para construir escaparates personalizados como la API de escaparate. Hoy hablaré sobre una de las preocupaciones más comunes relacionadas con el rendimiento que cualquier API impulsada por GraphQL eventualmente encontrará, el infame problema Nplusone.

Sin embargo, antes de comenzar, pensé que sería una gran idea darles una visión general de cómo se ve GraphQL en Shopify. GraphQL en Shopify comenzó en 2015 cuando tuvimos nuestro primer commit relacionado. Desde entonces, hemos acumulado más de seis esquemas de GraphQL para API internas y externas. Esos esquemas están compuestos por más de 5,000 tipos y mutaciones, y más de 1.7 millones de escaparates de comerciantes y 60,000 aplicaciones de socios son impulsadas por ellos. En total, nuestros puntos finales de GraphQL manejan un promedio de un millón de consultas por minuto. Puedes ver que GraphQL es muy importante en Shopify y nos hemos involucrado mucho en ello. En esta escala, el rendimiento es de suma importancia, así que hablemos sobre una de las principales causas de ralentización. Ese es el problema Nplusone.

¿Qué es? En pocas palabras, es lo que sucede cuando necesitas presentar una lista de objetos y cada objeto tiene un atributo almacenado en otro modelo. Estos suelen ser completamente separados del modelo principal y en una base de datos diferente. Veamos un ejemplo de esquema y veamos cómo estos problemas pueden manifestarse fácilmente. Como puedes ver, aquí tenemos un esquema bastante sencillo. Tenemos un tipo de artículo que tiene un título y un autor, y luego tenemos un tipo de autor que solo tiene un nombre. Finalmente, en nuestra raíz de consulta, tenemos un campo de artículos que nos proporciona una lista de artículos opcionalmente limitada al número que solicitamos. Detrás de escena, como dije, los artículos y los autores se almacenan por separado en la base de datos y están vinculados por sus respectivas IDs. Esta es una técnica bastante común conocida como normalización de bases de datos.

Entonces, ¿qué sucede detrás de escena cuando hacemos una consulta para un solo artículo? Puedes notar algunas cosas en estos registros de la aplicación. Primero, estamos ejecutando una aplicación impulsada por Ruby on Rails, que es el estándar en Shopify. Debido a eso, tenemos un potente marco de mapeo objeto-relacional, también conocido como ORM, llamado Active Record. Ese detalle no es tan importante en esta charla, ya que los problemas de n-plus-ones pueden aparecer sin importar el lenguaje o el marco que uses. Pero intentaré explicar las sutilezas aquí específicamente para aquellos que no están familiarizados con Rails o Ruby. En segundo lugar, puedes ver dos consultas SQL distintas que se realizan aquí. La primera busca un conjunto de artículos, en este caso solo uno, indicado por la cláusula de límite. La segunda busca un registro de autor por su ID, y ese ID proviene de la columna de ID de autor del artículo. Esto es un poco de magia de Rails detrás de escena. Todo eso tenía sentido y parecía relativamente inofensivo. Entonces, ¿qué sucede cuando solicitamos más de un artículo? Aquí es donde obtenemos nuestro primer vistazo al problema en cuestión. Veamos qué ha cambiado. Nuestra consulta de artículos no ha cambiado mucho, excepto que ahora la cláusula de límite solicita cinco en lugar de uno. Sin embargo, como puedes ver, por cada artículo que se resuelve, ahora realizamos una consulta SQL separada para obtener su autor. Es por eso que se llama un n plus 1, o para algunos de ustedes, un 1 plus n. Una consulta para la lista de objetos principales y luego n consultas, o en este caso, cinco, para obtener cada objeto secundario. Como puedes imaginar, si aumentamos el número de artículos solicitados, también aumenta el número de consultas de autor. También como nota al margen, puedes notar la palabra caché junto a la suma de las consultas de autor. Esto es una de las cosas que vienen con Rails y ActiveRecord. De forma predeterminada, se mantiene una caché consultada que evita viajes innecesarios a la base de datos cuando se solicita un registro específico por su ID. Esta función evita parte del dolor causado por el n plus 1, pero no siempre está disponible. Por ejemplo, si cada artículo tuviera un autor único, la caché nunca tendría la oportunidad de ser utilizada. Tampoco nos ayuda realmente en escenarios donde el registro secundario no se almacena en la base de datos. Puede estar almacenado en otro lugar, como un archivo local o un servidor HTTP remoto. Entonces, ¿cómo lo solucionamos? ¿Cómo nos aseguramos de que se realicen la menor cantidad posible de consultas a la base de datos? Antes de hablar sobre soluciones, debemos comprender cómo se resuelve la consulta de GraphQL detrás de escena. Nuevamente, estamos usando Ruby y para nuestra lógica de GraphQL, estamos usando la biblioteca de código abierto GraphQLRuby, que en realidad usamos en Shopify y contribuimos de vez en cuando. La mayoría de las implementaciones de GraphQL funcionan en función del concepto de resolvers. Un resolver es una función que sabe cómo tomar un objeto principal y devolver un cierto campo o atributo de ese objeto principal. De forma predeterminada, la implementación de GraphQLRuby simplemente llama al método con el mismo nombre que el campo en ese objeto y, como tenemos un objeto Active Record que se alinea perfectamente con ese esquema, todo funciona. Sin embargo, en la raíz, no tenemos un objeto principal, por lo que esos resolvers deben implementarse manualmente como ves aquí. Siguiendo la consulta de GraphQL paso a paso, primero visitamos el resolver de artículos que toma el argumento de límite que le damos y devuelve un conjunto de objetos de modelo de artículo. A partir de ahí, cada objeto de artículo se pasa a la implementación del tipo de artículo y sus campos se resuelven uno por uno. El título simplemente se establece en la propiedad de título del objeto de modelo. Cuando llega el momento de resolver el campo de autor, ocurre un poco de magia de Rails detrás de escena para consultar automáticamente la base de datos en busca del modelo relacionado. Luego, ese resultado se pasa al tipo de autor y así sucesivamente. Es esta consulta automática mágica para obtener el autor relacionado la que parece ser la raíz de nuestro problema. Entonces, ¿cómo lo solucionamos? Bueno, Rails tiene otro truco bajo la manga llamado Active Record Preloading. Al agregar otro modificador al final de nuestra consulta de artículo, Rails cargará automáticamente todos los autores únicos relacionados con el conjunto de resultados. Y como sabe de antemano quiénes son esos autores, puede hacerlo de manera eficiente en solo una consulta. Si observamos los registros, ahora podemos ver que solo se realizan dos consultas a la base de datos. Una para todos los artículos y otra para todos los autores relacionados. Ahora, hay otra diferencia en los registros más allá del número de consultas SQL, el tiempo de respuesta. Puede que estés pensando que ocho milisegundos no parece una gran diferencia. Sin embargo, para ponerlo en perspectiva, supongamos que nuestro punto final de GraphQL no es multiproceso. Solo puede manejar una solicitud a la vez. Esto es bastante común. Esos 8 milisegundos son la diferencia entre manejar 4,600 solicitudes por minuto y más de 12,000 solicitudes por minuto. Eso es muy importante. Entonces, ¿ya terminamos? Bueno, ¿qué sucede cuando hacemos una consulta en la que no nos importa el autor? Hm, eso es extraño. Aún estamos solicitando autores aunque no los estemos usando. Para entender por qué, tenemos que volver a cómo funcionan los resolvers.

4. Carga por lotes con resolutores perezosos

Short description:

Por defecto, comenzamos en la parte superior del gráfico y avanzamos hacia abajo. La biblioteca GraphQL Ruby tiene una función interesante que permite anticipar si se han solicitado ciertos campos y, en función de eso, hacer cosas condicionalmente, como precargar objetos secundarios. La anticipación de GraphQL Ruby resuelve el problema de saber cuándo precargar, pero hace que nuestros resolutores dependan demasiado entre sí. Existe una mejor manera llamada carga por lotes. La carga por lotes utiliza la ejecución perezosa de los resolutores, donde en lugar de devolver un valor, devuelve una promesa. La ejecución de esta promesa se retrasa hasta que se resuelve toda la consulta. Puede hacer referencia a un estado compartido vinculado a la duración de la consulta.

Por defecto, comenzamos en la parte superior del gráfico y avanzamos hacia abajo. Cuando estamos en el resolutor de artículos, no tenemos idea de qué campos se están solicitando debajo de nosotros. Por lo tanto, debemos asumir de manera codiciosa el peor escenario posible. El resultado es una consulta SQL potencialmente desperdiciada, lo que afecta el tiempo total de la solicitud. ¿Recuerdas hace cinco segundos cuando dije que no tenemos idea de qué campos se solicitan debajo de nosotros? Bueno, mentí un poco. La biblioteca GraphQL Ruby tiene una función interesante que permite anticipar si se han solicitado ciertos campos y, en función de eso, hacer cosas condicionalmente, como precargar objetos secundarios. Al verificar si se ha seleccionado el campo de autor, podemos agregar condicionalmente la precarga a nuestra consulta. Ahora solo estamos cargando lo que necesitamos. Por supuesto, esto funciona, pero hay un pequeño problema de diseño o filosófico aquí. ¿Debería este resolutor realmente preocuparse por lo que hacen otros resolutores? Fácilmente puedes meterte en un lío donde los resolutores hacen referencia a campos y si queremos hacer un cambio, podemos. Aquí puedes ver que estamos cargando hasta 10 niveles de profundidad, sin mencionar una dependencia circular. Así que recapitulemos nuestras opciones. Tenemos la precarga de registros, que es bastante mágica y fácil de agregar. Sin embargo, es codiciosa por defecto, ya que no sabemos si es necesario aguas abajo. También es importante saber que esto no nos ayuda si el objeto secundario no está almacenado en la base de datos. La anticipación de GraphQL Ruby resuelve el problema de saber cuándo precargar, pero hace que nuestros resolutores dependan demasiado entre sí. Tiene que haber una mejor manera, ¿verdad? Spoiler: sí la hay, y esto es algo que llamamos carga por lotes. La carga por lotes utiliza otra función impresionante de la biblioteca Ruby, la ejecución perezosa de los resolutores. La idea es bastante simple. En lugar de devolver un valor, devuelve una promesa. La ejecución de esta promesa se retrasa hasta que se resuelve toda la consulta, justo a tiempo antes de que el resultado esté listo para ser devuelto al cliente. Otra característica clave de estas promesas es que pueden hacer referencia a un estado compartido vinculado a la duración de la consulta. ¿Qué significa esto para nuestra aplicación de ejemplo? Veamos cómo podríamos usar un resolutor perezoso para resolverlo.

5. Carga por lotes y prevención de MPlusOnes

Short description:

En esta parte, exploramos la clase authorLazyLoader y cómo ayuda en la carga por lotes de recursos relacionados. También discutimos la biblioteca GraphQL Batch y sus beneficios para resolver problemas de carga de relaciones. Para prevenir MPlusOnes, Shopify utiliza técnicas como pruebas unitarias y entornos de preparación. Es importante optimizar las solicitudes de ida y vuelta y tener herramientas para reconocer resolutores no optimizados. Los MPlusOnes pueden ocurrir en otras APIs, no solo en GraphQL. Gracias, Jonathan, por la charla esclarecedora. Animamos a la audiencia a hacer preguntas en el chat para la próxima sesión de preguntas y respuestas. A continuación, tenemos a Alex, un gerente de ingeniería en Shopify, que hablará sobre la contextualización de GraphQL para la fijación de precios en diferentes países.

OK, tenemos mucho que abordar aquí, repasemos todo. A la izquierda, tenemos nuestro tipo de artículo y el resolutor de autor. A la derecha, tenemos la nueva clase llamada authorLazyLoader, eso es un poco complicado. Devolveremos la propiedad de la clase al autor y devolveremos un valor. Llamaremos a la instancia de esta clase como nuestra promesa en lugar de buscar el autor de inmediato. El cargador perezoso se inicializa con dos cosas, un contexto y un artículo. El contexto es un estado compartido que mencioné anteriormente. Está disponible para todos los resolutores y su ciclo de vida está vinculado a la ejecución de la consulta. En este contexto, el cargador perezoso almacena un hash o un diccionario que contiene dos conjuntos de IDs. Uno de los IDs que se nos ha solicitado cargar y los IDs que ya hemos cargado.

Cada vez que se crea y devuelve una instancia de este cargador perezoso, estamos construyendo esa lista de IDs de autor que necesitamos buscar. Cuando llega el momento de cumplir la promesa, la biblioteca Ruby llama al método author, del cual hablamos cuando definimos nuestro esquema. Puedes ver eso en la parte inferior izquierda. En este método, verificamos nuestro estado compartido para ver si ya hemos cargado el autor específico que se nos solicita. Si no lo tenemos, consultamos la base de datos para buscar todos los autores que hemos recopilado hasta ahora. Finalmente, devolvemos el autor que se encontró.

Ahora, echemos un vistazo a los registros y veamos qué sucede. Esto se parece a cuando usamos la precarga de Rails, lo cual es bueno, sin embargo, brilla realmente cuando realizamos la consulta sin solicitar el autor. Genial. Ahora los registros de autor no se cargan en absoluto y el resolutor de artículo no se da cuenta. Lo que es aún mejor de este enfoque es que facilita la carga de recursos relacionados desde otras bases de datos, servicios externos de Redis o incluso un sistema de archivos. Puedes agrupar las solicitudes para optimizarlas lo máximo posible. En Shopify, creemos que la carga por lotes en GraphQL es muy buena, de hecho, hemos creado una biblioteca de código abierto en torno a ella, llamada GraphQL Batch. Esta biblioteca lleva lo que te mostré anteriormente a un nivel mucho más refinado, reutilizable y poderoso, y es el estándar de facto en Shopify para resolver cualquier tipo de problema de carga de relaciones en nuestros esquemas. Con esta biblioteca, podemos crear fácilmente un cargador por lotes genérico y reutilizable para manejar muchas situaciones diferentes. Aquí tienes algunos ejemplos de cargadores por lotes que hemos utilizado en el pasado en Shopify, uno para cargar relaciones de Active Record y otro para buscar en la caché de Rails. Usando la clase ActiveRecordLoader, nuestro resolutor de campo de autor podría verse algo como lo que ves a la derecha.

Ahora, hemos visto qué son los MPlusOnes y cómo los resolvimos con algunos enfoques, pero ¿cómo nos aseguramos de que no vuelvan a ocurrir? ¿Cómo evitamos que las consultas extremadamente poco eficientes se envíen a producción y arruinen todo? Bueno, la respuesta es mucho más difícil de lo que parece. En Shopify, tenemos algunas técnicas para ayudar a prevenir que los MPlusOnes nos causen dolores de cabeza a nosotros y a nuestros comerciantes. La primera de ellas se llama pruebas unitarias. Es posible que hayas oído hablar de ellas. Cada tipo y mutación en cada esquema que tenemos tiene una prueba unitaria correspondiente para probar la lógica empresarial del resolutor. Un requisito que aplicamos mediante el linting en nuestro entorno de CI es que cada tipo de esquema también debe tener un caso de prueba correspondiente para verificar las precargas. En nuestro esquema de ejemplo, tendríamos una prueba de precarga para el tipo de artículo. Esta prueba simplemente llama a una sola línea, un método auxiliar proporcionado por nuestra biblioteca interna de pruebas compartida. La implementación de este ayudante itera sobre cada campo del tipo y busca cualquier ruta de código no optimizada conocida que no esté agrupada en la base de datos, Redis u otros. Desafortunadamente, esta prueba requerida no es infalible. Debido a que es automatizada, hay ciertos campos que no podemos probar, como aquellos con argumentos requeridos. Por ejemplo, esos tipos de escenarios se manejan cuando se agregan casos de prueba dedicados a través de nuestros procedimientos de revisión de código manual. Además de las pruebas unitarias que podemos hacer en entornos estáticos, también aprovechamos entornos de preparación similares a la producción donde se pueden probar y monitorear cambios de GraphQL mucho más grandes en busca de regresiones. Utilizando instrumentación y métricas a nivel de base de datos, podemos ver picos en el rendimiento y luego, con suerte, rastrearlos hasta la consulta y la solicitud individuales, y encontrar el código sospechoso. En resumen, hemos aprendido que los MPlusOnes pueden afectar gravemente el rendimiento de la ejecución de las consultas, lo que a gran escala puede significar la diferencia entre manejar 1,000 solicitudes por minuto o 1,000,000 solicitudes por minuto. Debes aprovechar varias técnicas para optimizar y limitar el número de solicitudes de ida y vuelta a tu base de datos, o para minimizarlas si son excesivas. También es fundamental tener herramientas para reconocer resolutores no optimizados y asegurar que el rendimiento se mantenga a lo largo del tiempo. Además, debes saber que si bien nos hemos centrado en GraphQL hoy y nuestros ejemplos están escritos en Ruby y Rails, los MPlusOnes también pueden ocurrir en otros lugares. Las API REST tradicionales o el concepto de API REST también tienen una relación de modelo. Esto puede suceder. Eso es todo por hoy. Gracias. Muchas gracias, Jonathan. Fue increíble. Nuevamente, me gustaría reiterar para nuestros invitados y agradecerles por unirse a nosotros, para aquellos que se unieron más tarde. Siéntanse libres de hacer sus preguntas en la función de chat. Vamos a responder algunas preguntas y luego veremos quién puede ser nuestro próximo orador. Tomaremos nota de eso y, en la tercera hora, tendremos una AMA adecuada con todos los oradores, incluido otro de los oradores, que dará una charla relámpago la próxima semana. Ha podido unirse a nosotros. Así que sigan enviando sus preguntas. Asegúrense de que si tienen algo que necesite aclaración, déjenlo en el chat. Sin más preámbulos, creo que pasaremos a nuestro próximo orador, que resulta ser Alex. Alex, ¿te importa desactivar el silencio y saludar a todos, mientras preparo tu charla? Hola a todos. Soy Alex. Soy un gerente de ingeniería en Shopify en el equipo de fijación de precios. Hemos estado trabajando recientemente en la contextualización de GraphQL para mostrar precios en diferentes países. Así que eso es de lo que hablará la charla de hoy. Y trabajé en esto con Lana, que también está aquí con nosotros hoy para ayudar a responder preguntas y demás. Fantástico. ¿Lana, quieres saludar también? Hola a todos. Soy Lana. Como mencionó Alex, hemos estado trabajando juntos en la contextualización de GraphQL para... Y sí, estoy en Ottawa, así que contáctame si quieres tomar un café o tienes alguna pregunta sobre directivas.

6. Contextualizando las APIs de GraphQL con Directivas

Short description:

Hola a todos. Mi nombre es Alex. Soy un gerente de ingeniería en Shopify. Hoy, estoy muy emocionado de hablar con ustedes sobre un desafío que enfrentamos a gran escala en Shopify, la contextualización de las APIs de GraphQL. Discutiremos el contexto, el problema que enfrentamos y las cuatro enfoques diferentes que consideramos: encabezados, argumentos y el enfoque del espectador. En última instancia, elegimos las directivas. Explicaré qué es una directiva, proporcionaré ejemplos de directivas personalizadas y predefinidas, y discutiré cómo podemos crear las nuestras propias. En Shopify, tenemos la API Storefront, una API de GraphQL que impulsa las tiendas personalizadas. A medida que los requisitos cambiaron, introdujimos la multi-moneda y la fijación de precios internacionales, lo que llevó a la necesidad de una API de GraphQL más contextualizada. Exploramos el uso de encabezados y argumentos, pero encontramos limitaciones en su capacidad para admitir la versión de la API y garantizar una experiencia de cliente consistente. El enfoque del espectador mostró promesa pero no cumplió completamente. Fue entonces cuando descubrimos las directivas como la solución. Ahora, profundicemos en los detalles de cómo funcionan las directivas y sus beneficios.

Sí, así que pasaré esto a Alex. Muy bien, muchas gracias, Alex y Lana. Si tienen preguntas, nuestros oradores están aquí. Pero por ahora, compartiré mi pantalla nuevamente y comenzaré la sesión.

Hola a todos. Mi nombre es Alex. Soy un gerente de ingeniería en Shopify. Y hoy, estoy muy emocionado de hablar con ustedes sobre un desafío que enfrentamos a gran escala en Shopify, la contextualización de las APIs de GraphQL. Entonces, hoy, lo que voy a hablar primero es el contexto y el problema que estamos tratando de enfrentar, los cuatro enfoques diferentes que utilizamos para intentar resolver este problema y, en última instancia, el que elegimos, las directivas. Les hablaré sobre qué es una directiva, ejemplos de directivas personalizadas y predefinidas, y cómo podemos crear las nuestras propias. Antes de entrar en detalles, todas las buenas charlas de GraphQL comienzan con una consulta. Les daré un poco de contexto sobre cómo llegamos aquí. En Shopify, tenemos varias APIs y una de esas APIs se llama API Storefront. Es una API de GraphQL que impulsa las tiendas personalizadas. Una de las consultas más básicas que harás cuando muestres una tienda es mostrar productos, como una camiseta, sus variantes, como el tamaño o el color de ese producto, y luego su precio, lo que el cliente pagará por él. Y esta es una consulta muy básica. Aquí estamos viendo eso y estamos devolviendo el producto, las variantes y el precio de $7.00 USD. Hasta ahora, no hay problemas. Pero, como con todas las grandes plataformas de software, nuestros requisitos están cambiando con el tiempo. Entonces, Shopify introdujo la multi-moneda, donde los clientes pueden comprar productos en diferentes monedas según lo que deseen pagar. Hemos evolucionado nuestra API de GraphQL para incluir un nuevo campo llamado precios de presentación. Aquí puedes ver que tenemos el producto, sus variantes y el campo de precios de presentación, que toma un argumento de monedas de presentación. Entonces, en este caso, estoy obteniendo los precios, pero para dólares australianos. Esto funciona como esperas. Devolvemos la respuesta que tiene la misma cantidad, pero convertida a dólares australianos. Esto es realmente útil si puedes imaginar una tienda personalizada que tiene un selector de moneda donde puedes seleccionar en qué moneda el cliente desea comprar. Nuevamente, es relativamente simple, por lo que aún no hemos tenido demasiados problemas.

Y, como puedes imaginar, nuestros requisitos cambian una vez más. Shopify introdujo una nueva función llamada fijación de precios internacionales. Bajo este modelo, ya no mostramos precios basados en una moneda, sino en la ubicación geográfica de la persona. Por ejemplo, podrías tener un cliente en Francia que paga 10 euros, pero un cliente en Italia que también paga en euros podría gastar 15 euros en el mismo producto. Y esto podría basarse en diferentes factores que el comerciante desea controlar, como el margen o cualquier tipo de centro de costos que necesiten tener en cuenta. Entonces, estamos comenzando a ver este problema en el que tenemos una API de GraphQL que al principio era simple, pero está introduciendo más y más requisitos, y nuestras experiencias se están volviendo más y más contextualizadas según la ubicación del comprador, lo que el comprador necesita ver, y así sucesivamente. Entonces, necesitábamos una API que admitiera esto. Un poco más de contexto aquí es que no era tan simple como que necesitábamos mostrar solo precios. Necesitábamos mostrar el precio, necesitábamos mostrar el precio de comparación, que es algo como el precio de venta sugerido, necesitábamos mostrar rangos de precios, cuáles son los precios mínimos y máximos para un producto y otros campos que necesitan tener en cuenta dónde se encuentra el comprador. También sabíamos que nos estábamos moviendo hacia un modelo donde, nuevamente, nuestras experiencias se están volviendo cada vez más contextualmente conscientes. Por ejemplo, queremos contextualizar una tienda según la ubicación minorista preferida del cliente para poder mostrar información, como cuánto está disponible en stock para que lo recojan en la tienda. Ahora tienes el problema de lo que necesitábamos resolver para una API de GraphQL más contextualizada basada en la experiencia del comprador. Voy a profundizar en los diferentes enfoques que utilizamos para intentar resolver este problema.

Entonces, primero tenemos los encabezados. Aquí estás viendo los encabezados que podríamos pasar para contextualizar la API. Sabíamos que ya estábamos pasando un encabezado de token de acceso para que los clientes de la API obtuvieran acceso a los campos que están solicitando, por lo que pensamos que podrían pasar otro encabezado con el país como argumento. Sería algo sencillo porque los clientes de la API ya están enviando estos encabezados y podríamos obtener ese valor y devolver la respuesta correcta en función de eso. Los aspectos positivos aquí son que todos los campos se resolverán al precio correcto del país con esa moneda, no hubo grandes cambios en el esquema de la API, por lo que los clientes existentes podrían adoptarlo. Pero, por otro lado, una de las razones por las que amamos tanto GraphQL es que es un sistema tipado. Por lo tanto, no hay forma de que podamos validar proactivamente que el código de país que se envía en el encabezado sea uno válido que admitamos. Tampoco admite nuestro sistema de versión y deprecación de la API. Introducimos APIs cada tres meses y no habría una forma sencilla para que los clientes de la API sepan si se introduce un nuevo contexto o si se elimina uno a medida que desarrollamos nuevas funciones. Por lo tanto, se vuelve muy difícil de manipular con el tiempo. Por esa razón, los encabezados no parecían ser la solución. El siguiente enfoque que tomamos fueron los argumentos. Esta es lo que yo diría que es la solución más simple que podría funcionar. Podríamos agregar un argumento de código de país a cada campo que lo necesite. Aquí puedes ver que estamos obteniendo el producto. Sus variantes nuevamente, pero en este caso tenemos un precio con un argumento de Francia, un precio de comparación con un argumento de Francia y un rango de precios con un argumento de Francia. Los aspectos positivos aquí son que es muy explícito. Definitivamente no hay confusión sobre qué campos devolverán qué valores. También nos beneficiamos de que esté en nuestra definición de esquema y tenga esas validaciones. Por lo tanto, sabemos que solo podemos enviar un argumento de código de país a estos campos. También tenemos el soporte de versión de la API que mencioné antes, podemos evolucionar esto con el tiempo a medida que introducimos nuevos argumentos o los eliminamos. Pero los aspectos negativos aquí son que abre la posibilidad de que los clientes de la API agreguen diferentes valores a diferentes campos. Realmente queríamos asegurarnos de que solo ofreciéramos una experiencia de cliente consistente y parece un poco incómodo que puedas mostrar el precio para Francia, pero un precio de comparación para Italia. Además, a medida que introducimos más campos y más contexto, como la compra en línea, recoger en la tienda, deberás agregar esos argumentos a cada campo que lo necesite. Aquí puedes ver el ejemplo de cómo eso podría no funcionar tan bien. Tienes el precio para Francia, un precio de comparación para Estados Unidos y un rango de precios para Italia.

Nuestra siguiente opción que consideramos fue el enfoque del espectador. Esto es algo que GitHub utiliza en su API de GraphQL para mostrar información de usuario autenticado. En este enfoque, tenemos un campo de nivel superior llamado espectador que toma un solo argumento de país para Francia y luego el resto de los campos se resuelven debajo de él para producto, variante y precios. Esto va en la dirección correcta. Ahora, cuando resolvemos esta respuesta, estamos devolviendo una experiencia consistente que tiene precios solo en euros, solo para Francia.

7. Directivas para Consultas Contextuales de GraphQL

Short description:

De esta manera, el país se pasa una vez y está disponible para todos los campos. Llegamos a la solución de introducir una nueva directiva llamada in context. Establece el país una vez y es compatible dentro de nuestro esquema. Los clientes pueden agregar fácilmente esta directiva a sus consultas sin tener que reescribir completamente.

De esta manera, el país se pasa una vez y está disponible para todos los campos, y nuevamente, es compatible en nuestro esquema. Por lo tanto, tenemos todos los beneficios de agregar y eliminar argumentos con el tiempo. Los contras aquí son que mantener otro campo raíz es un poco engorroso y duplica mucho del comportamiento existente en nuestra API. Pero además de esto, solo hemos estado hablando de consultas, pero cualquier otra mutación que necesite devolver estas respuestas contextuales también debe actualizarse para que devuelva un espectador que también devuelva esta información.

Estamos llegando muy cerca aquí y comenzamos a ver un patrón de lo que queremos, y así es como llegamos a las directivas. Esta es la mejor manera. Entonces, la solución en la que nos decidimos es introducir una nueva directiva llamada in context. Aquí puedes ver que estamos consultando productos en Francia con una directiva at in context que toma un solo argumento de país, Francia. Similar al espectador, luego todos los otros campos debajo de él, tenemos variantes de productos y sus precios. Y se resuelven a un precio de país único y una moneda única. Los aspectos positivos aquí son que el país se establece una vez y está disponible para todos los campos. Es compatible dentro de nuestro esquema y también es mucho más fácil para los clientes adoptarlo de inmediato. No tienen que reescribir por completo sus consultas. Solo tienen que agregar esta directiva in context y beneficiarse a partir de ahí.

8. Uso de Directivas en GraphQL

Short description:

Las directivas proporcionan una forma de describir el comportamiento de ejecución en tiempo de ejecución y la validación de tipos en un documento GraphQL. Se pueden utilizar para cambiar el comportamiento en tiempo de ejecución y se clasifican como directivas de tiempo de ejecución y directivas de esquema. Las directivas de tiempo de ejecución, como include y skip, modifican el comportamiento del ejecutor de GraphQL. Las directivas de esquema, como deprecated, anotan el esquema y proporcionan información a los clientes y herramientas. Las directivas personalizadas se pueden utilizar para diversos fines, como traducciones, temas, control de acceso y transformaciones. La gema GraphQL Ruby de Shopify ofrece una directiva de transformación para la manipulación de campos de cadena. La construcción de directivas personalizadas es sencilla y se pueden adjuntar al esquema con un método de resolución que define su comportamiento. En resumen, exploramos el problema de contextualizar las API de GraphQL, los diferentes enfoques que consideramos y cómo las directivas surgieron como una solución. Las directivas proporcionan flexibilidad para modificar el comportamiento de GraphQL y son una herramienta valiosa a considerar cuando sea necesario.

Ahora que vemos las directivas para nuestro winner, es posible que te estés preguntando, ¿qué es una directiva? Así que vamos a profundizar en eso. Las directivas proporcionan una forma de describir el comportamiento de ejecución en tiempo de ejecución y la validación de tipos en un documento GraphQL. Lo que esto significa es que una directiva describe algún comportamiento que deseas tener y el ejecutor de GraphQL actualiza el resultado en función de esta dirección o información adicional. La implementación de GraphQL debe proporcionar las directivas include y skip. Por lo tanto, ya hay dos directivas incorporadas que se pueden usar o que quizás ya hayas usado. Veamos cómo usarlas para darte una idea de cómo se ve una directiva. Aquí tenemos una consulta de producto que tiene un argumento include price que es un booleano. Estamos obteniendo el producto, las variantes, un ID y estamos incluyendo opcionalmente este campo de precio si el argumento include price es verdadero. Cuando se resuelve, si el valor de include price es falso, entonces el precio no se devuelve en nuestra respuesta. Sin embargo, si include price es verdadero, el valor se devuelve en nuestra respuesta. De esta manera, la directiva include está dando una dirección al ejecutor de GraphQL sobre cómo debe responder a la consulta. También tenemos la directiva incorporada skip, que es lo mismo que include, pero con un comportamiento opuesto. Estas son lo que llamamos directivas de tiempo de ejecución, lo que significa que editan el comportamiento en tiempo de ejecución. También tenemos otro tipo de directiva llamada directivas de esquema. Una directiva de esquema con la que quizás estés familiarizado es la directiva deprecated. Aquí puedes ver un ejemplo de un producto que tiene un campo antiguo etiquetado como deprecated. Proporciona una razón, use el nuevo campo en su lugar, y luego tenemos un nuevo campo también. Lo que la directiva de esquema está diciendo es que está anotando el esquema para darnos un poco de información sobre cómo usarlo, y esto es realmente útil porque tenemos herramientas como GraphiQL, cuando tienes una directiva deprecated en un campo, aparece un subrayado amarillo junto con un mensaje emergente que dice, hey, no uses esto. Estos son los tipos de directivas que tenemos. Entonces, ¿cómo podrías usar directivas personalizadas y para qué podrías usarlas? Algunos ejemplos podrían ser traducciones o temas. Activación de funciones o control de acceso, y transformaciones. Una gema que usamos en Shopify llamada GraphQL Ruby, por ejemplo, proporciona una directiva de transformación que te permite transformar un campo de cadena para que esté en mayúsculas o minúsculas, entre otras cosas. Por lo tanto, está dando instrucciones adicionales sobre cómo el ejecutor de GraphQL debe resolver esos campos. Ahora que tenemos una idea de qué es una directiva, ¿por qué no construimos una? Por ejemplo, echemos un vistazo a los requisitos que queremos cumplir para esta directiva. Tenemos una consulta de una página de producto, y ahora queremos introducir una directiva de tema que actualmente tiene dos variaciones, una variación oscura y una variación clara. Y cuando resolvemos esta consulta de página de producto, vamos a devolver diferentes colores de fondo, colores de primer plano y una URL de imagen diferente según este tema. Entonces, cuando le paso la variación oscura, la directiva se asegurará de que los resolutores respondan con colores oscuros y luego una imagen de marcador de posición oscura. Y cuando paso la variación clara, responderá con colores más claros y una imagen de marcador de posición clara. En Shopify, muchas de nuestras aplicaciones utilizan Ruby y Ruby on Rails, y también usamos una gema llamada GraphQL Ruby, a la que contribuimos de vez en cuando para alimentar nuestras definiciones de esquema de GraphQL. Por lo tanto, los ejemplos que voy a presentar ahora están en Ruby utilizando la gema GraphQL Ruby, pero el enfoque puede ser aplicable a muchos otros lenguajes y marcos que tengas. Aquí estamos definiendo una directiva llamada tema, que hereda de la clase de directiva proporcionada por GraphQL Ruby. Toma un argumento, en nuestro caso, uno de los tipos de enumeración de variación de tema, y es obligatorio. También se le asigna una ubicación. Aún no hemos hablado de esto, pero las directivas se definen en diferentes ubicaciones. Por ejemplo, las directivas in context que introducimos para resolver nuestro problema se definieron a nivel de consulta porque es el nivel más alto al que se aplica la directiva. Otro ejemplo de una ubicación es el nivel de campo, que es donde se definen las directivas include y skip. Aquí, esta directiva se aplica a nivel de campo individual para que esos campos se resuelvan en lugar de toda la consulta que nuestro tema quiere resolver. Y una vez que hemos definido nuestra directiva, la adjuntamos al esquema simplemente dándole la declaración de la directiva. En GraphQL Ruby, también debes definir un método de resolución que nos indique cómo se comportará la directiva cuando se resuelva. Y el método de resolución toma tres argumentos, un objeto, los argumentos de la directiva y el contexto. Lo que estamos haciendo en esta directiva es que primero queremos obtener la variación del tema que queremos usar. Vamos a encontrar el tema en función de este nombre de variación. Y luego vamos a establecer el valor en el contexto para que pueda ser utilizado por cualquier resolutor que lo necesite. Luego, en nuestros tipos, aquí tenemos nuestro tipo de producto con los campos de color de fondo, color de primer plano y de imagen. Y luego también tenemos nuestro tipo de imagen con el campo de URL. Y en GraphQL Ruby, para resolver estos campos, todo lo que tienes que hacer es definir un método que corresponda al nombre de ese campo. Entonces, para usar nuestra directiva de tema, lo que tenemos que hacer es primero obtenerla del contexto que se nos ha proporcionado. Y luego encontramos el tema para ese producto y devolvemos el color de fondo correcto que está contextualizado por esta directiva. Para la URL, podemos hacer lo mismo porque el valor está en el contexto, también podemos resolverlo aquí. Obtenemos el tema del contexto y luego resolvemos la imagen en función de esto. Y esto funciona de manera similar a cómo lo hace la directiva in context. Encontramos el argumento del código de país, establecemos el valor en el contexto y cualquier campo que necesite usar ese contexto puede hacerlo. En resumen, ¿qué aprendimos? Primero, presentamos el problema de contextualizar nuestras API de GraphQL a medida que evolucionan con el tiempo, y aprendimos que cuando estamos resolviendo un problema difícil, debemos probar diferentes enfoques para evaluar los pros y los contras. Es algo que les animo a todos a hacer porque las directivas no fueron nuestra primera opción. De hecho, fue la última opción que exploramos, y fue bueno que hayamos investigado estas diferentes opciones para encontrar la que se ajustara a nuestros requisitos en ese momento. También aprendimos que las directivas en nuestro caso funcionan porque nos dieron una forma de cambiar el comportamiento en tiempo de ejecución. Construimos directivas personalizadas y aprendimos lo fácil que es hacerlo. Es otra herramienta en nuestro conjunto de herramientas que debemos considerar cuando sea necesario. Muchas gracias por escuchar. Espero que hayas encontrado útil esta charla, y espero tus comentarios y preguntas. Muchas gracias, Alex y Lanna, los apreciamos. Creo que la próxima persona en el escenario es Theo. Estoy tratando de mantenerlo en marcha para que tengamos suficiente tiempo al final para preguntas durante la hora de AMA. Theo, déjame ver si estás aquí. Si lo estás, por favor, desactiva el silencio, enciende tu video. Y me encantaría que saludes a las personas que se han unido mientras preparo tu charla. Hola Marcy, hola a todos en el streaming. Sí, me alegra estar aquí. Mi nombre es Theo, soy un gerente de desarrollo en Shopify. Lidero un equipo móvil aquí que trabaja en el producto principal y estoy basado en Ottawa.

9. Optimización de GraphQL para Dispositivos Móviles

Short description:

Hoy, cubriremos el rendimiento de GraphQL en dispositivos móviles, la medición e interpretación del rendimiento, el diseño de paginación, las estrategias de consulta para nuevos campos y la consulta paralela. La optimización para dispositivos móviles es crucial debido a las redes más lentas e inestables, la escalabilidad y el envío más rápido, y la atención del usuario a los tiempos de carga.

¡Fantástico, excelente material! Así que vamos a empezar de inmediato. Voy a compartir mi pantalla nuevamente. Hola a todos, mi nombre es Theo. Soy un gerente de desarrollo en Shopify. Lidero el equipo de desarrolladores de iOS y Android. Hoy quiero hablar sobre algunas de las estrategias de consulta de GraphQL que hemos descubierto a lo largo de los años en Shopify. Lo primero que quiero mostrarte es la gestión gratuita de consultas en Shopify Mobile. GraphQL es un lenguaje fantástico para clientes móviles, especialmente debido a la seguridad de tipos y al rendimiento. Tiene una sinergia fantástica con dichos clientes. Si aún no lo has probado, te animo a que lo hagas.

¿Qué vamos a cubrir hoy? El rendimiento de GraphQL en dispositivos móviles, también conocido como por qué estamos haciendo esto, y algunos de los resultados previstos que intentamos lograr a través de las estrategias de consulta. También veremos cómo medir el rendimiento de manera precisa e interpretar los resultados. Diseñaremos teniendo en cuenta la paginación y las estrategias de consulta para nuevos campos, como cuando estás implementando una nueva función. Concluiremos la charla con la consulta paralela.

Entonces, ¿por qué optimizar para dispositivos móviles? Parece muy obvio, pero la primera razón es optimizar para redes más lentas e inestables. No siempre tenemos la ventaja de contar con una red estable, o puede haber caídas repentinas cuando las personas entran al metro, por ejemplo. Por lo tanto, debemos aprovechar al máximo la capa de consulta, ya sea a través de la caché o simplemente mejorando el rendimiento, para asegurarnos de que siempre tengamos algo que mostrar o al menos acercarnos a ese ideal. Además, nos permite escalar y enviar más rápido. Si ya estableces un patrón sólido desde el principio en tu capa de consulta, no tendrás que preocuparte demasiado por cargar nuevos campos en cada pantalla. Esto debería resultar en una escalabilidad y un envío más rápidos en tu aplicación. Además, los tiempos de carga son más escrutados por los usuarios, especialmente en dispositivos móviles, porque los usuarios consumen contenido a un ritmo más rápido debido al tamaño de la pantalla y terminan desplazándose, buscando e interactuando más. Por lo tanto, esto también es importante en términos de enfoque de experiencia de usuario.

10. Medición de TTI y Estrategias de Consulta

Short description:

Ahora vamos a discutir TTI (Tiempo para Interactuar) y su importancia en la medición de la interacción del usuario en aplicaciones móviles. TTI combina el tiempo de consulta y el tiempo de renderizado, y establecer umbrales para cada producto es crucial. Factores como los tiempos de carga, el rendimiento de la red, el tiempo de renderizado, el modo del dispositivo y el ciclo de vida de la vista afectan el TTI. La paginación es una estrategia efectiva de consulta para listas infinitas, asegurando un buen rendimiento y escalabilidad. Implementar nuevos campos de manera segura en una aplicación móvil requiere considerar múltiples versiones en vivo y evitar problemas de datos faltantes.

Ahora que hemos hablado sobre por qué es importante mejorar la capa de consulta, hablemos de cómo vamos a medir nuestros juegos. En Shopify, utilizamos lo que se llama TTI (Tiempo para Interactuar). Define el momento en el que comenzamos a cargar la pantalla hasta el momento en que el usuario puede interactuar con ella. Esencialmente, es el tiempo de consulta más el tiempo de renderizado. Tenemos algunas estrategias en móviles para que sea un poco más suave y disimular algunos de los tiempos de carga. Vamos a hablar puramente del tiempo desde que se instancia el controlador de vista de pantalla hasta que se renderiza y se puede interactuar.

Cuando hablamos de TTI, es necesario establecer umbrales para cada producto, ya que son diferentes. No se puede esperar lo mismo dependiendo del contenido que se desea mostrar en la aplicación. Las personas pueden tener una mejor tolerancia a los tiempos de carga cuando se trata de contenido más grande, como videos e imágenes. Para el texto, puede ser un poco diferente. Esto es algo a tener en cuenta, ya que los ejemplos que vamos a ver deben interpretarse en función de su propio producto y aplicación.

También queremos construir una medición precisa y hay muchos factores que pueden hacer que su TTI sea incorrecto en términos de interpretación. Por lo tanto, vamos a repasar esto. En primer lugar, hablemos de los umbrales. Este es un modelo simple en el que se puntúa del uno al cero en función del tiempo que tarda en cargar la página y hacerla interactiva. Obtenemos uno si es menos de un segundo, 0.5 si está entre uno y dos segundos, y cero si es más de dos segundos. Según ese promedio, obtenemos una puntuación de consulta. Así es como se mide prácticamente cada pantalla. Nuevamente, los umbrales son muy diferentes para cada producto, por lo que debe asegurarse de tener en cuenta que las puntuaciones más altas representan lo ideal. Le recomiendo que sea muy agresivo. Cuanto más agresivo sea, generalmente más matizada será la puntuación de consulta y mayor será la mejora que obtendrá. Aquí solo tenemos tres umbrales, pero también puede tener más en su producto.

¿Qué pasa con el contexto de rendimiento? Hablamos de redes celulares. Es importante tenerlo en cuenta al medir el TTI. También debemos pensar en el tipo de rendimiento que buscamos en cada tipo de red, desde 3G hasta WiFi. Esto es algo importante a tener en cuenta, ya que afectará la interpretación de la puntuación de TTI. Luego, el tiempo de renderizado versus el tiempo de consulta. Esto también es importante. Probablemente mejorará su capa de consulta a medida que pase el tiempo, pero también es importante tener en cuenta el tiempo de renderizado y diferenciar ambos cuando se trata de la herramienta de TTI en términos de promedio. Luego, el modo del dispositivo. No todos los dispositivos pueden tener el mismo rendimiento. Esto afectará directamente el tiempo de renderizado para algunos, especialmente si se muestra una interfaz de usuario compleja y animaciones. Luego, el ciclo de vida de la vista también. ¿Cuándo exactamente está llamando al evento de inicio y al evento de finalización? ¿Con qué frecuencia lo hace? La implementación puede variar entre clientes, entre la forma en que se mide en la web, iOS y Android. Esto también es algo a tener en cuenta al implementar la instrumentación.

Saltemos a nuestra primera estrategia de consulta, que es la paginación. Es bien conocida, pero la cubriremos rápidamente. Esta es la lista ordenada, que es una de las pantallas más importantes en la aplicación móvil de Shopify. He trabajado en esta pantalla durante varios años y mostramos una lista infinita de pedidos que son necesarios para que los comerciantes interactúen, ya sea para cumplir o administrar. En este ejemplo, tenemos nuestra primera página de 25 pedidos. Nuevamente, es una lista infinita a medida que se desplaza hacia abajo. Cuando te acercas a 25, es cuando vamos a activar la página dos. Esto nos permite tener un rendimiento muy bueno, ya que no tenemos que preocuparnos por cuántos pedidos en cada tienda vamos a poder admitir. Esto es lo que parece desde una perspectiva de GraphQL. Tiene dos parámetros en los puntos finales de los pedidos. La altura de la página, que será 25. Y también especificar después de qué página quieres cargar. La primera será opcional en cadena. Será para el ID de la página, que será nulo la primera vez que lo llames porque comienzas desde la página cero. Pero después de eso, obtendrás el ID de la página cuando llames a la segunda página. Y también tenemos el campo hasNextPage en la información de la página, que nos indica si hay una página siguiente para cargar y evitar que la pantalla se congela al final cuando estás en la última página. Es tan simple como eso. Realmente te animo a implementarlo para que sea escalable cuando estés lidiando con una lista infinita. Incluso una lista finita, pero siempre hará que toda la implementación sea más rápida. Y además, no tienes que preocuparte tanto por la escalabilidad si, por ejemplo, tu modelo de negocio cambia y ahora, en lugar de una lista fija de 50 elementos, tienes un número infinito o un número mucho mayor. Pero realmente no puedes admitir en clientes móviles. Nuevamente, una lista infinita con un gran rendimiento se puede lograr a través de la paginación. Y también se trata de hacerlo bien desde el principio, luego obtendrás una escalabilidad automática prácticamente para siempre, a menos que los campos de cada elemento sean demasiado grandes y luego debas reconsiderar tanto tu UX como tu consulta.

Estrategias de consulta para nuevos campos. Aquí vamos a hablar sobre cómo implementar de manera segura nuevos campos en la aplicación móvil. Vamos a analizar específicamente dos enfoques diferentes, comparar los pros y los contras. Puedes implementar nuevos campos a través de las etiquetas add, include, add, skip. Vamos a analizar más a fondo cómo se ve el ejemplo y la consulta de GraphQL en este caso. También puedes duplicar consultas y sí, vamos a comparar el impacto de cada enfoque. Algo a tener en cuenta al lidiar con un cliente móvil es que tienes múltiples versiones en vivo al mismo tiempo en producción. En este ejemplo, vamos a agregar un nuevo campo llamado precio del peaje en la versión 1.1, eliminarlo en la versión 2.0. El problema aquí es que si la versión 1.1 todavía está en producción en el momento en que eliminamos el precio del peaje, es probable que tengamos un bloqueo, un caso de datos faltantes u otros problemas inesperados. Si falta un campo cuando se realiza la consulta desde una perspectiva de GraphQL, es probable que la consulta falle.

11. Optimización de Consultas en GraphQL

Short description:

Para optimizar las consultas en GraphQL, puedes utilizar el enfoque de omitir/incluir o duplicar las consultas. El enfoque de omitir/incluir es fácil de implementar y escalar, pero no es seguro para el trabajo en progreso. Duplicar las consultas es más seguro para el trabajo en progreso y no se ve afectado por cambios en los campos, pero requiere más esfuerzo y puede volverse complejo. La consulta paralela puede mejorar significativamente el rendimiento al dividir los fragmentos en consultas separadas y ejecutarlas en paralelo. Este enfoque escala en el lado del servidor y hace que los clientes móviles sean más rápidos. Sin embargo, requiere una inversión inicial y una nueva capa de consulta en el lado del cliente.

De lo contrario, tendrás que implementar extensas medidas de seguridad desde la perspectiva de un cliente móvil. Esto es el precio del peaje que estamos implementando aquí. He tomado un ejemplo del campo que ves a la derecha, que será el precio del peaje de cada pedido. Y lo que queremos hacer en el primer enfoque es utilizar la etiqueta de inclusión. Tendremos una bandera, que es un booleano llamado priceEnable como principal en nuestra consulta, y este es nuestro fragmento en este momento para cada fila que ves, cada pedido incluido si la bandera booleana es verdadera. Si la bandera booleana es falsa, entonces el precio será nulo en su mayoría. Esto hace que tu campo sea nulo y es muy fácil de incluir cuando quieres marcar algo y evitar que se cargue en tu consulta de GraphQL.

El segundo enfoque que puedes tomar es duplicar todos los fragmentos. Ahora he cambiado el nombre del fragmento base y lo llamo detalles del pedido con precio. Lo incluyo directamente sin ningún tipo de bandera aquí. El marcado ocurrirá cuando estés realizando la consulta. Así que he creado una segunda consulta para eso, que llama a este nuevo fragmento. Y en el momento de la ejecución, básicamente seleccionarás cada consulta en función de la bandera adecuada. ¿Cuáles son los pros y los contras de cada enfoque? Así que omitir/incluir, ya lo hemos visto. Es muy fácil de implementar. Es prácticamente un trabajo de una sola capa. En el lado de las consultas duplicadas, es un poco más difícil. Tienes que duplicar tu consulta. También tienes que incluir tal vez un sistema de marcado más complicado. Así que sí, ten en cuenta que hemos tomado un ejemplo de una consulta muy simple, pero a medida que crece, puede ser más difícil de duplicar. Omitir/incluir, gran contra. No es seguro para el trabajo en progreso. Si el campo cambia de nombre, se mueve o se elimina por completo, nuevamente, te enfrentarás a un bloqueo debido a la versión. Y las consultas duplicadas, en cambio, son seguras para el trabajo en progreso porque técnicamente en producción, si has hecho tu trabajo con tu bandera de función local, entonces nunca consultas por ella. Sabemos que nunca está en producción a menos que estemos listos. En el lado de omitir/incluir, tienes una implementación fácil. Lo mismo ocurre con las consultas duplicadas. Creo que si has hecho tu trabajo correctamente con tu bandera local, no debería ser demasiado difícil. Omitir/incluir es fácil de escalar. Puedes tener múltiples omitir/incluir dentro de la misma consulta y confiar en diferentes banderas. O las consultas duplicadas, es un poco más difícil. Es exponencial porque necesitarás todas las posibilidades de consulta con cada función, lo que significa que si tienes dos banderas, por ejemplo, en lugar de tener dos consultas duplicadas, necesitarás cuatro, necesitarás una donde ambas banderas sean verdaderas, una donde la bandera uno sea verdadera, una donde la bandera dos sea verdadera y una donde todas las banderas sean falsas. Esto lo hace un poco más difícil y si tienes tres o cuatro de esto, se vuelve aún más complicado. Así que esto puede funcionar solo cuando estás implementando una función a la vez.

Omitir/incluir se rompe con cualquier cambio de campo, prácticamente lo mencionamos. Si mueves un campo, lo renombras, lo eliminas desde la perspectiva del backend, entonces sí, podría causar un bloqueo o sí, simplemente falta de datos desde la perspectiva del cliente, dependiendo de cómo manejes los errores. Las consultas duplicadas, por otro lado, son inmunes a los cambios de nombre y eliminación. Así que si tienes equipos muy grandes, como tenemos en Shopify, podría ser también el mejor camino a seguir para asegurarte de que tu cliente no se vea afectado en producción.

Ahora que hemos hablado sobre las implementaciones y la paginación, podemos echar un vistazo a la consulta paralela. Así que vamos a mantener el mismo ejemplo, pero esta vez vamos a utilizar la pantalla de detalles para cada pedido. En la aplicación móvil de Shopify, si alguna vez la has utilizado, es muy grande. Cargamos una tonelada de información, la línea de tiempo, la tarjeta de pago, la lista de elementos de línea, que nuevamente puede ser muy grande, la lista de cumplimientos, la lista de devoluciones, y así sucesivamente, solo por mencionar algunos de ellos. El problema que teníamos prácticamente con esta implementación es que debido a que la consulta seguía creciendo y creciendo, nos enfrentábamos a tiempos de carga importantes y ya lo hemos presenciado en wifi. Así que nos preocupaba que la aplicación en este punto pudiera colapsar en ciertos escenarios con una red más lenta. No creemos que sea aceptable hacer esperar a nuestros comerciantes durante cinco segundos en cada tiempo de carga, especialmente porque esta es una de las funciones más utilizadas en la aplicación. Así que el enfoque que tomamos desde esta consulta inicial es dividir cada fragmento por consulta cuando sea posible. En lugar de tener el ejemplo que tenemos aquí, que son cinco frameworks diferentes dentro de la misma consulta, optamos por cinco consultas con un fragmento cada una. Luego las ejecutamos en paralelo. Todo es asíncrono. No las encadenamos. Y luego ensamblamos algunas declaraciones una vez que hemos recopilado suficiente información para mostrar. Se ve así prácticamente. Una vez más, cada fragmento se ha dividido en cada consulta y el resultado es que consideremos que comenzamos desde un tiempo de carga total de dos milisegundos. El nuevo tiempo de carga es el más alto entre cada consulta. Esto también te da una perspectiva de cuál consulta es la más larga. Y tal vez comiences a pensar en la representación parcial para que puedas reducir aún más el tiempo de interacción. Nuevamente, el tiempo de interacción no es la finalización en términos de todas las consultas, sino cuando el usuario puede comenzar a interactuar. Esto también puede ofrecerte una perspectiva diferente. Así que aquí pasamos directamente de dos segundos a 800 milisegundos, lo cual es una gran mejora, pero puedes reducirlo aún más y puedes dividir nuevamente, más y más cada fragmento en múltiples consultas. Para resumir este enfoque, escalas en el lado del servidor para que los clientes móviles no tengan que hacerlo y esto hace que los clientes móviles sean más rápidos. La consulta paralela mueve la carga al lado del servidor. Creemos que es un enfoque mejor simplemente porque escalar en el lado del servidor es más fácil que escalar en el lado del cliente. El problema con este enfoque es que en su mayoría requiere una inversión al principio cuando estás haciendo la transición. En el lado del cliente, necesitarás una nueva capa de consulta completa. Probablemente requerirá pruebas extensas y probablemente una forma de simular la cadena de posibles eventos de consulta, como fallas intempestivas, éxito parcial, puede ser un poco difícil, pero definitivamente vale la pena. También ayuda a equilibrar y distribuir las caídas de rendimiento en cada punto final.

12. Distribución Eficiente de Consultas y TTI

Short description:

En lugar de bloquear todo el hilo con una consulta gigantesca, distribuir los esfuerzos puede equilibrar la carga del servidor. Sincronizarse primero con el backend garantiza que no haya problemas de rendimiento. El TTI se determina por el tiempo de carga de la consulta y el tiempo de renderizado.

En lugar de bloquear prácticamente todo el hilo de nuevo con una consulta gigantesca, distribuyes tus esfuerzos. Esto puede hacer que el rendimiento en términos de carga del servidor, sea un poco más equilibrado en el lado del backend. Nuevamente, realmente depende de cada punto final que estés consultando. Entonces, si sigues este camino, la forma en que lo hemos hecho en Shopify, al menos en el equipo móvil es sincronizarse primero con el backend. para asegurarnos de que esto no cause problemas de rendimiento en el lado del backend. Y tu nuevo TTI, como mencionamos, es el tiempo de carga de la consulta más el tiempo de renderizado. Por lo tanto, está siendo moldeado bastante. Especialmente porque el tiempo de carga de la consulta en nuestro caso era mucho, mucho mayor que el tiempo de renderizado.

13. Greg McWilliam sobre la construcción del producto API del mañana

Short description:

Gracias por escucharme y no dudes en contactarme si tienes alguna pregunta o quieres discutir la consulta paralela. Greg es nuestro próximo ponente y hablará sobre la construcción del producto API del mañana. En Shopify, las versiones de esquema se realizan según un cronograma trimestral, mientras que las características se desarrollan a largo plazo. Los meta-campos son pares clave-valor personalizados que se pueden adjuntar a los principales tipos de recursos principales. Agregar un nuevo tipo principal crea desafíos para representar los valores futuros en las versiones de esquema. Estrategias como los tipos de marcador de posición no implementados y la nulabilidad simple pueden ayudar a abordar estos desafíos.

Eso es prácticamente todo. Gracias por escucharme y no dudes en contactarme si tienes alguna pregunta o si quieres discutir la consulta paralela, que en su mayoría es un enfoque bastante nuevo que hemos estado probando, es probable que lo refinemos. Te animo a que comentes al respecto y sí, gracias de nuevo. Veo aplausos por todas partes. Muchas gracias Theo. Fue increíble. Me gustaría reiterar, si tienes alguna pregunta, no dudes en escribirla en la función de chat. Vamos a tener una AMA adecuada al final durante la última hora de esta masterclass y todos nuestros ponentes estarán allí para responder tus preguntas. Y si quieres, también podemos invitarte al escenario si te gustaría hacer tu pregunta en persona, pero creo que sigamos con dos charlas más si no me equivoco, Greg es nuestro próximo ponente. Y antes de cargar tu charla, Greg, no dudes en activar el sonido, saludar a todos y luego comenzaremos.

Hola a todos. Soy Greg McWilliam, estoy en el equipo de plataforma de contenido y extensiones de datos trabajando en llevar datos extensibles al núcleo de Shopify y espero compartir algunos pensamientos y notas contigo. Fantástico, muy bien, gracias Greg. Greg todavía está aquí, estará allí incluso si la charla está pregrabada, así que no dudes en interactuar con él en el chat, pero déjame compartir mi pantalla ahora y comenzar.

Hola, GraphQL Galaxy. Mi nombre es Greg McWilliam. Soy un ingeniero principal en el equipo de plataforma de contenido y extensiones de datos. Y hoy estoy aquí para hablar sobre la construcción del producto API del mañana. Probablemente estemos familiarizados con el patrón de lanzar temprano, lanzar con frecuencia. Hacemos esto todo el tiempo. Entonces, el código ingresa a la rama principal y cuando estamos construyendo APIs, eso se traduce en una nueva versión de esquema. Por lo tanto, implementamos un dominio que actualiza la aplicación, actualiza tu esquema y tenemos una nueva versión de esquema para acompañar el nuevo código de la aplicación. Podemos hacer esto varias veces al día, día tras día, y también lo hacemos dos veces los miércoles, una vez los jueves. No implementamos los viernes porque, ya sabes, fin de semana. En Shopify, seguimos más bien el enfoque de lanzar tarde, lanzar correctamente. Lo que quiero decir con eso es que nuestras versiones de esquema se realizan según un cronograma establecido. Por lo tanto, hacemos versiones de esquema trimestrales. Una vez al trimestre, lanzamos un nuevo esquema público oficialmente compatible. Y en comparación, nuestras características se desarrollan en plazos de tiempo muy largos. De hecho, podríamos comenzar a implementar una nueva característica en la rama principal, digamos al comienzo del año 21. Y esa característica podría tardar hasta, ya sabes, el cuarto trimestre del 21 antes de que realmente la lancemos. Y cuando la lanzamos, no hay garantía de que la pongamos disponible a través de la API. Podría ser lanzada solo como una característica exclusiva del administrador para que la uses dentro de nuestras pantallas de administrador, dentro de nuestras APIs de liquid, pero en realidad no la proporcionamos a través de una API pública de GraphQL. hasta posiblemente varios trimestres adicionales hasta que resolvamos todo y estemos listos para admitir el acceso a la API. Esto crea una situación interesante en la que nuestros datos de la aplicación se mueven a un ritmo diferente que nuestro esquema. Así que hablemos de eso. Y para hacerlo, echemos un vistazo a los meta-campos.

Entonces, ¿qué son los meta-campos? Los meta-campos son pares clave-valor personalizados. Se pueden adjuntar a muchos de los principales tipos de recursos principales como una tienda, un producto y un pedido. Y los meta-campos permiten que los tipos nativos se amplíen con atributos personalizados definidos por el comerciante. Entonces, si eres un comerciante que vende palos de hockey, así es como agregarías una clasificación de flexibilidad a tus productos de palos de hockey, estableciendo un meta-campo para ello. Entonces, los meta-campos pertenecen a una colección finita de todos los tipos principales nativos en cualquier versión de esquema dada. ¿Qué sucede si luego agregamos un nuevo tipo principal? Aquí estamos viendo un ejemplo de esquema. Tiene una clave, un valor para un meta-campo. Y luego, este recurso principal que estamos diciendo es una tienda, un producto, una variante de producto o un pedido. Y esto es lo que hemos lanzado públicamente. Ahora, detrás de escena, estamos haciendo desarrollo interno y actualizamos nuestra aplicación para permitir que el cliente sea un objetivo de meta-campo. Esto crea una situación interesante. Nuestra database ahora contiene nuevos valores principales pero esos valores no tienen representación en los esquemas públicos. Entonces, nuestra database contiene referencias a productos y pedidos. De repente, nuestra database también puede contener referencias a clientes. Sin embargo, los esquemas antiguos en realidad no incluyen el tipo de cliente en el recurso principal de meta-campo. Entonces, si intentáramos tomar uno de estos valores más nuevos y representarlo en un esquema más antiguo, terminaríamos con uno de estos errores de objeto en tiempo de ejecución donde el cliente no es un tipo posible para el recurso principal de meta-campo. Esto es complicado. Necesitamos estrategias para representar valores futuros en las versiones de esquema. Un tipo de marcador de posición no implementado es una opción. Entonces, con un marcador de posición no implementado, donde construimos algo llamado recurso no implementado que no tiene nada más que un ID porque sabemos que siempre tendremos un campo de ID en los nuevos objetos que ponemos a disposición. Y este recurso no implementado es simplemente un marcador de posición, que dice que los nuevos valores tienen una forma de representarse en esquemas más antiguos. No podrás interactuar con ellos de manera significativa. Sin embargo, no producirán errores. Esta es una opción. Hay una opción más simple. La nulabilidad simple puede limitar el impacto de estos posibles errores. Entonces, antes estábamos viendo que el recurso principal era un campo no nulo. Se garantizaba que estuviera presente. Y simplemente hacerlo nulo, no necesariamente resuelve el error que vimos antes. Sin embargo, lo localiza y localizarlo es mucho más útil a largo plazo para el desarrollo a largo plazo. Entonces, en realidad, hablemos de la nulabilidad porque esta es una opción bastante importante para planificar esquemas y admitirlos a largo plazo. Para mí, la nulabilidad no necesariamente promete que un valor exista tanto como promete que el valor se resolverá sin errores. Por ejemplo, solo estamos viendo que, podríamos saber que un meta-campo siempre tiene un tipo de propietario, pero es posible que no podamos resolverlo sin errores en todos los esquemas, momento en el cual la nulabilidad ayuda. Entonces, la nulabilidad realmente fue responsable de algunos de los conflictos que tuvimos.

14. Nullbubbling y Campos Nulos

Short description:

Nullbubbling ocurre cuando un campo de nivel bajo viola su contrato nulo, causando que su objeto padre sea invalidado. Esta cadena de invalidación puede propagarse hasta la raíz, resultando en la pérdida de todo el contenido. Para abordar esto, podemos colocar estratégicamente campos nulos para localizar errores dentro del gráfico. Los valores no nulos son adecuados para valores hoja garantizados por una restricción de base de datos, mientras que los campos nulos brindan flexibilidad para el desarrollo futuro del esquema.

¿Qué es el nullbubbling? El nullbubbling ocurre cuando un campo de nivel bajo viola su contrato nulo y invalida su objeto padre. En este ejemplo que estamos viendo aquí, en el tipo de dinero, supongamos que el campo decimal de cantidad se resuelve como nulo por alguna razón. Entonces, el padre se invalida y se convierte en otro valor nulo, lo cual puede violar el contrato nulo de su padre y esta cadena de invalidación puede propagarse hasta la raíz. Así que esa cantidad decimal que resultó ser nula puede invalidar a su padre y eso invalida a su padre. Y así sucesivamente, obtenemos algo que se ve más o menos así. El nullbubbling puede invalidar todos los datos resultantes en respuesta a errores de campo aislados. Así que tuvimos ese error en el campo de cantidad en una posición bastante baja dentro del documento. Y sin embargo, lo que terminamos viendo en los datos resultantes es que perdemos todo el contenido porque ese error de nivel bajo se propagó por todo el árbol. Todo se prometía como no nulo y luego todo se invalidó como resultado de eso. Esto no es ideal. Por lo tanto, lo que nos gustaría hacer es detener la propagación estratégicamente. La propagación se detiene en el primer ámbito nulo que se encuentra. Eso significa que la ubicación estratégica de campos nulos permite que los errores de resolución se localicen dentro del gráfico. En este caso, si esa cantidad decimal fuera nula, al menos podríamos contenerla de esta manera, permitiendo campos nulos, los errores se localizan sin bloquear la resolución del resto del documento. Así que aquí hemos visto que se produjo el mismo error en el campo de cantidad. Sin embargo, en lugar de invalidar todo el documento, lo único que perdemos es el campo de rango de precios, que tuvo ese valor nulo que se propagó unas cuantas capas para invalidarlo. Pero aún nos permitió resolver el producto padre y la consulta raíz que buscábamos. Esto es definitivamente mejor. En general, los valores no nulos son más apropiados para valores hoja que están garantizados por una restricción de base de datos. Estos serían objetos codificados en el espacio de nombres que estamos construyendo dentro de un resolvedor que sabemos que podremos producir. Y luego, los objetos codependientes donde uno resuelto exitosamente garantiza que el otro también se resolverá. De lo contrario, los campos nulos brindan flexibilidad para el desarrollo futuro del esquema al dejar agujeros nulos en lugares donde no estamos seguros de qué sucederá. Nos brinda mucha capacidad para innovar en el futuro y trabajar en torno a estos contratos flexibles en lugar de estar limitados por garantías rígidas para los datos.

15. Scoping Metafield Values

Short description:

Los valores de los metacampos pueden representarse como cadenas o formatos estructurados. Al implementar un ámbito dedicado, podemos mantener la intención singular del campo de valor al permitir un crecimiento futuro y rutas de acceso adicionales.

También hablemos sobre el ámbito. Continuando con el ejemplo de los metacampos por un momento aquí, los valores de los metacampos son cadenas. Sin embargo, los accesos adicionales pueden representar estos valores en formatos estructurados. Al observar nuestro tipo de metacampo, tiene una clave, tiene un valor, es una cadena, y esa cadena puede ser `hola mundo`, o podría ser esta GID de una referencia de producto Shopify. Y así, en el caso de que esto contenga una referencia, en realidad construimos este tipo de objeto de referencia aquí. Y esto es lo que nos permite obtener una selección completa de las referencias de los metacampos en sí. Así que en lugar de obtener solo una cadena GID que recuperamos del metacampo, y luego tenemos que hacer una segunda solicitud para obtener el objeto real al que hace referencia. Podemos obtener eso de una vez. Podemos obtener la GID como valor, y luego también podemos hacer una selección completa del producto de la tienda, la variante del producto o el pedido al que se hace referencia. Así que eso es útil. Sin embargo, a medida que se implementan nuevos tipos de valores estructurados, estos patrones de acceso pueden volverse confusos. Esta es una situación en la que estamos pensando en este momento. Nada de esto es definitivo, pero estamos considerando cómo implementar los valores de los metacampos como matrices. Y sabemos que sabemos en algún tipo de conexión de matriz que te daríamos, y eso podría confundirse con el valor como un valor simple. Y luego, por supuesto, la referencia sigue flotando. En general, hay mucho sucediendo aquí. Y estamos empezando a perder el control, ya sabes, de cómo realmente obtener el valor de esto a medida que agregamos estas rutas de acceso adicionales. Y aquí es donde un ámbito dedicado podría ayudar. Se mantiene la intención singular del campo de valor al abrir rutas de implementación de valor. Entonces, aquí, el valor del metacampo es un campo singular. Siempre sabemos cómo obtener un valor de metacampo porque solo hay un valor. Y luego, ese objeto de valor es un ámbito dedicado donde podemos obtener implementaciones específicas. Y el ámbito está estructurado de tal manera que anticipa el crecimiento futuro. En general, dar espacio a los ámbitos para crecer es útil para el desarrollo futuro.

16. Rebecca Friedman sobre APIs e Infraestructura

Short description:

Consideremos dos mutaciones como ejemplo simple. La segunda mutación tiene espacio para crecer, permitiendo errores estructurados y artefactos adicionales. Anticipando los tipos de región futuros, el patrón de uno-de es una solución versátil que funciona hoy. La versión de aplicaciones de forma independiente de los esquemas requiere una planificación y consideración constantes. Los campos nulos ofrecen flexibilidad futura y los ámbitos de objetos intermedios proporcionan espacio para crecer. ¡Gracias a todos y disfruten de GraphQL Galaxy!

Consideremos estas dos mutaciones como un ejemplo muy simple de esto. ¿Cuál de estas tiene espacio para crecer? Entonces, en la primera, tenemos market create one que tiene una entrada que recibe y luego devuelve el objeto de mercado que se construyó en comparación con market create two aquí, que recibe esa misma entrada. Y en lugar de devolver directamente el objeto de mercado, devuelve un market create payload y ese payload ofrece el objeto de mercado como un campo. Entonces, el segundo puede parecer más verboso y simplemente innecesariamente pesado en el esquema. Y sin embargo, la ventaja del segundo es que tiene espacio para crecer. Podríamos terminar en el futuro dándonos cuenta de que queremos dar errores específicos para esta transacción. Y esto nos da un lugar para dar errores estructurados. Podríamos querer dar artefactos instantáneos que se construyen junto con la creación de un mercado nuevamente tenemos un lugar para hacer eso. Si solo estuviéramos dando el mercado directamente entonces perderíamos la capacidad de ir y hacer que los resultados de esta transacción sean más inteligentes con el tiempo. Entonces, esto también tiene que ver con cómo hacemos las entradas a largo plazo. ¿Cómo estructuramos nuestro código de tal manera que podamos recibir entradas que crezcan con nuestra aplicación? Y así, estábamos hablando de mercados en el último ejemplo. Así que sigamos hablando de mercados. ¿Qué son los mercados? Un mercado configura ajustes para vender internacionalmente. Configura moneda, idioma, dominio, etc. y una tienda puede tener muchos mercados y configurar estratégicamente los ajustes por regiones objetivo. Entonces, cada mercado puede apuntar a una o más regiones geográficas juntas y las regiones del mercado son países pero esto puede variar eventualmente por granularidad para extenderse a provincias y códigos postales o hacia arriba a cosas que son más grandes que un país como bloques. Entonces, lo que necesitamos hacer es anticipar la presentación de tipos de región futuros pero no tenemos ni necesitamos uniones de entrada porque tenemos el patrón de uno-de. Entonces, lo que estamos tratando de hacer es decir hoy estamos recibiendo códigos de país y una región de mercado es solo un país. Solo recibirá códigos de país pero sabemos que en el futuro es posible que queramos enviar códigos de provincia. Es posible que queramos enviar códigos de estado. Es posible que queramos enviar códigos postales. Y así queremos design una estructura para la entrada que anticipará el crecimiento con esta necesidad. Entonces, este patrón de uno-de es genial porque decimos que vamos a configurar una de estas entradas. Podemos poner tantas claves de entrada únicas como queramos en ella. Y luego simplemente escribimos una regla de validación que dice que esta entrada responderá exactamente a uno de estos tipos de entrada. Entonces, hoy podemos estar creando mercados que contienen solo países pero en el futuro podríamos mezclar y combinar un país más una provincia más un código postal podría componer una estrategia de segmentación de mercado. Entonces, por qué nos gusta el patrón de uno-de. Es más versátil que la propuesta de uniones de entrada. Los miembros pueden incluir objetos de entrada, valores de enumeración, escalares o listas. La verdadera belleza de esto es que funciona hoy utilizando estructuras GraphQL simples. Hoy, podemos hacer cumplir este patrón utilizando validaciones en el lado del servidor. Y en el futuro, si se adopta la especificación de uno-de esto se convertiría en una validación a nivel de GraphQL e incluso podríamos eliminar las validaciones en el lado del servidor que hacen este tipo de cosas. Puedes leer esto de nuevo, échale un vistazo. Lo usamos mucho. Es uno de nuestros favoritos para diseñar entradas que anticipen el crecimiento futuro.

Entonces, gracias a todos. Disfruten de GraphQL Galaxy, y nos vemos más tarde en la sesión del panel. Cosas impresionantes. Gracias, Greg. Fue fantástico. Veo muchos comentarios, algunas preguntas allí. Vamos a responder eso durante el AMA. Solo nos queda uno de los cinco temas así que pasemos a ese último, definitivamente no el menos importante, Rebecca también será nuestra oradora aquí. Rebecca, no sé si estás aquí. Siéntete libre de desactivar el silencio, saludar a todos, y luego comenzaremos tu grabación. Genial. Hola, soy Rebecca Friedman. Soy una gerente de desarrollo en Shopify. Gestiono nuestras API e infraestructura, así que me enfoco tanto en push como en pull. Vivo en el Reino Unido. Mi trabajo es gestionar tanto las API de push como de pull. Hablaré más sobre lo que hace nuestro equipo en el video. Y estoy basada en Toronto, Canadá, y en realidad alguien de mi equipo también está aquí. Así que Guy, preséntate. Sí, claro. Mi nombre es Guilherme Piera. Trabajo con Rebecca en el equipo de finanzas de API. No tengo una charla en este taller, pero tengo una charla relámpago el 9 de diciembre. Sí, te invito a echarle un vistazo. Hablaré sobre otros usos de GraphQL además de las API HTTP. Genial. Gracias. Gracias, Guy.

17. Rebecca Friedman sobre la gestión de grandes APIs de GraphQL

Short description:

Hola a todos. Mi nombre es Rebecca Friedman y soy una gerente de desarrollo en Shopify. Hoy les hablaré sobre el trabajo que ha realizado nuestro equipo de patrones de API para facilitar la gestión de grandes APIs de GraphQL. Identificamos y establecemos las mejores prácticas para el diseño de APIs de GraphQL, pero también somos responsables de un código fundamental que permite a los desarrolladores diseñar y construir esas APIs. Revisamos los cambios en el esquema de GraphQL y evaluamos la calidad de los nuevos tipos y campos que se agregan. También revisamos la implementación del esquema, asegurándonos de que no falten pruebas y evaluando el diseño general de la API. Para agilizar el proceso de revisión, creamos una aplicación de GitHub llamada GraphQL Schema Bot que utiliza las acciones de GitHub para identificar y señalar problemas comunes de GraphQL en las solicitudes de cambio de esquema. Esto nos permite centrarnos en el diseño general y no distraernos con tareas manuales. Nuestra aplicación realiza una serie de acciones, como vincular el esquema, crear problemas de GitHub para las descripciones actualizadas e integrar un linter como una verificación en nuestro flujo de trabajo de integración continua (CI pipeline).

Gracias, Rebecca. Permítanme compartir mi pantalla ahora mismo. Y esta será la última de las cinco charlas y luego comenzaremos nuestra reunión A.

Hola a todos. Mi nombre es Rebecca Friedman y soy una gerente de desarrollo en Shopify. Actualmente gestiono nuestras APIs y el grupo de infraestructura. Y hoy les hablaré sobre el trabajo que ha realizado nuestro equipo de patrones de API para facilitar la gestión de grandes APIs de GraphQL. Así que los llevaré atrás en el tiempo y les hablaré sobre algunos de los obstáculos que hemos enfrentado y cómo los hemos superado.

Mencionamos antes que hay más de 5,000 tipos, enumeraciones, entradas, uniones y escalares en nuestros esquemas. Eso es mucho. Y con todos los desarrolladores en Shopify y somos muchos, eso significa que las APIs están evolucionando rápidamente y que diferentes partes de la API están evolucionando simultáneamente. Entonces, la misión de nuestro equipo de patrones de API es avanzar en las mejores prácticas de API y hacerlas más fáciles de usar. Y evolucionar la infraestructura fundamental para los creadores de API. Por lo tanto, hacemos varias cosas, identificamos y establecemos las mejores prácticas para el diseño de API de GraphQL, pero también somos responsables de un código fundamental que permite a los desarrolladores diseñar y construir esas APIs. Tenemos nuestra propia capa de abstracción sobre el RubyGem de GraphQL que proporciona métodos de conveniencia para patrones de código comunes como definir y validar identificadores globales.

Entonces, ¿cómo estamos involucrados en el diseño y desarrollo de API? Bueno, normalmente no construimos APIs nosotros mismos pero estamos en la intersección de muchos equipos diferentes que construyen APIs. No somos guardianes de las APIs, somos administradores. Confiamos en que construyas la API tú mismo pero estamos como en segundo plano para asegurarnos de que tu API esté bien diseñada y sea consistente con nuestras APIs existentes. También estamos buscando activamente tendencias en cómo se están desarrollando las APIs y los tipos de decisiones de diseño que los equipos deben tomar. Y luego utilizamos eso para establecer y formalizar las mejores prácticas. Desde el principio, hemos estado brindando comentarios a los desarrolladores a través de revisiones técnicas de diseño pero también a través de revisiones de código.

Nuestro equipo tiene una persona dedicada al ATC cada día que es responsable de brindar soporte a los equipos internos. ATC significa Controlador de Tráfico Aéreo y nuestro ATC escalara o clasificará los problemas que surjan y revisará las solicitudes de cambio y luego estará atento a los paneles operativos. Cuando reflexionamos sobre qué específicamente estábamos revisando en las solicitudes de cambio, nos dimos cuenta de que había varias cosas distintas. Entonces, primero, el diseño del esquema. Revisamos los cambios en el esquema de GraphQL y los utilizamos para evaluar la calidad de los nuevos tipos y campos que se agregan. ¿Son consistentes con otros tipos ya presentes en el esquema? ¿Los nombres de los campos tienen sentido? Y luego, en segundo lugar, revisamos la implementación del esquema. Es decir, el código del resolvedor Ruby y la estructura del código de cualquier nueva preocupación o módulo agregado. Nos aseguramos de que no falten pruebas unitarias u otras pruebas de integración. Y luego, en tercer lugar, la función en su conjunto. Por lo tanto, evaluamos el diseño general de la API. ¿Es esta una buena solución para el problema que se está resolviendo? ¿Cuál es la experiencia que tendrá un desarrollador al interactuar con esta API? Aquí hay una captura de pantalla de una sesión de lluvia de ideas donde enumeramos las cosas que buscábamos durante las revisiones de diseño de esquema. Así que pueden ver muchas cosas interesantes aquí. Nos preocupa la estructura de entrada y la estructura de los campos, los nombres de las mutaciones y los nombres de los tipos y la calidad de las descripciones de todo, si los campos tienen los tipos correctos, y especialmente si están utilizando escalares personalizados cuando deberían hacerlo. Si las personas entienden el polimorfismo y si están utilizando uniones e interfaces correctamente, y la pregunta siempre presente de ¿cómo están utilizando la nulabilidad? Por lo tanto, revisar las solicitudes de cambio parecía una excelente manera de asegurarnos de que las APIs estuvieran evolucionando en una dirección con la que estuviéramos satisfechos, pero hubo algunos problemas.

Como pueden ver en nuestra sesión de lluvia de ideas teníamos todas estas listas de verificación mentales que estábamos siguiendo. Estas eran como todas estas tareas manuales repetitivas que estábamos realizando, lo cual indica que podría haber una oportunidad para la automatización en algún lugar. Y luego la calidad de las revisiones era inconsistente en todo el equipo, a veces debido a la antigüedad del revisor en el equipo, ¿verdad? Entonces, alguien que llevaba tiempo en el equipo tenía opiniones más sólidas o podía ver indicios en las solicitudes de cambio que llevaban a problemas subyacentes. Y luego la revisión de las solicitudes de cambio era solo parte del rol de ATC. Entonces, si estabas abrumado con otro trabajo de alta prioridad, las solicitudes de cambio se relegaban a una verificación rápida que era más como, ¿estás haciendo algo terrible aquí? Si no, probablemente esté bien enviarlo. El siguiente problema fue que nuestros equipos no crecieron al mismo ritmo que Shopify. Entonces, más desarrolladores significaban más solicitudes de cambio para que cada ATC las revisara y el volumen estaba creciendo sin control. Creo que también había esta presión autoimpuesta de trabajar en toda la cola de solicitudes de cambio abiertas durante tu turno de ATC. Y al mismo tiempo, para no perder nada importante en todas esas revisiones. Entonces, la rotación de ATC se volvió estresante. Siempre está el factor del mejor escenario, ¿y si alguien es atropellado por un autobús? Había mucho conocimiento tribal en nuestro equipo sobre cómo diseñar buenas APIs. Y lo estábamos difundiendo a través de la revisión de solicitudes de cambio para que el conocimiento tribal creciera a lo largo de los años siendo partes interesadas de otros equipos. Y luego, cuando las personas dejaban nuestro equipo o eran atropelladas por un autobús, que es lo mismo claramente, probablemente veríamos una disminución en la calidad de la revisión de solicitudes de cambio. Y luego el último punto, creo que el punto de inflexión fue que nuestro equipo no estaba contento porque sabíamos que nos estábamos perdiendo problemas de diseño más grandes porque estábamos usando nuestro tiempo para resolver estos problemas más básicos.

Entonces, esto es lo que hicimos. Creamos una aplicación de GitHub que utiliza GitHub Actions para identificar y señalar problemas comunes de GraphQL en las solicitudes de cambio de esquema. Así que eso es un poco complicado pero básicamente cualquier solicitud de cambio que agregue nueva funcionalidad a la API o cambie la funcionalidad existente, produce cambios en el esquema. Y estos cambios en el esquema los incluimos en la solicitud de cambio junto con nuestros cambios de código. Entonces, ahí está la clara oportunidad de aprovechar el esquema como una revisión completa del diseño en su conjunto. Oh, y nuestra aplicación se llama GraphQL Schema Bot. Entonces, cada vez que se abre una solicitud de cambio, realizamos una serie de acciones. Vinculamos un esquema. Y si hay descripciones que se están actualizando, creamos un problema de GitHub para los redactores técnicos para que puedan revisarlos. Calculamos algunas estadísticas sobre la solicitud de cambio. ¿Qué esquemas están cambiando? Porque tenemos varios. ¿Están realizando cambios incompatibles en la API? ¿Cuántos cambios están realizando? Cosas así. Y luego integramos el linter como una verificación en nuestro flujo de trabajo de integración continua (CI pipeline). Entonces tenemos dos verificaciones. La primera es si se están realizando cambios incompatibles, requerimos que el autor de la solicitud de cambio lo reconozca manualmente. Por lo tanto, tendrían que hacer clic en el botón de aprobar cambios en la captura de pantalla. Entonces eso les hace conscientes una última vez del impacto que su cambio podría tener en la comunidad de desarrolladores. Y luego, la segunda es si hay violaciones del linter, anotamos la solicitud de cambio. Lo que estamos haciendo es abstraer todas las tareas que una computadora puede hacer mejor que nosotros. Y filtramos el ruido para que cuando revisemos las solicitudes de cambio, podamos centrarnos en el diseño general y no distraernos. Aquí hay una lista de todas nuestras reglas de linter.

18. Análisis del Linter de GraphQL y Tutorial de Diseño

Short description:

El Linter de GraphQL en Shopify tiene 16 reglas, con cinco agregadas en 2021. Su objetivo es guiar a los desarrolladores hacia el mejor diseño de API de GraphQL, pero permite circunstancias atenuantes y limita los falsos positivos. Las reglas aseguran consistencia y fomentan el pensamiento crítico sobre el diseño del esquema. Ejemplos incluyen prohibir términos de interfaz de usuario en los nombres de los campos, agrupar campos con prefijos comunes en tipos separados y definir campos de retorno de mutaciones con manejo de errores. El Tutorial de Diseño de GraphQL, publicado en 2018 y actualizado regularmente, presenta 23 reglas de diseño y enfatiza la creación de subobjetos para campos estrechamente relacionados. El tutorial también discute la estructura de las cargas de mutación y la importancia del manejo de errores.

Es una lista bastante larga, pero señalaré algunas cosas interesantes. En primer lugar, hay 16 reglas aquí. En 2021, agregamos cinco de ellas. Por lo tanto, nuestro Linter no cambia tanto. Y creo que eso se debe en parte a que no hay reglas controvertidas en él. Tenemos tres niveles de violaciones del Linter. Tenemos advertencias, fallas y luego avisos. Casi nunca rechazamos las solicitudes de cambio cuando estamos aplicando el Linter. La mayoría de las veces, solo estamos agregando sugerencias. Y puedes ver eso aquí. He indicado si algo es una sugerencia o un requisito. Los únicos diseños de esquema que requerimos son que necesitas tener descripciones que sean frases completas. Tenemos un formato específico que esperamos para los campos de retorno de mutación. Y luego debes usar letras mayúsculas para los valores de enumeración. Utilizamos las fallas del Linter con moderación porque, aunque las reglas del Linter están destinadas a dirigirte hacia el mejor diseño de API de GraphQL, siempre puede haber circunstancias atenuantes. Por lo tanto, estamos tratando de limitar los falsos positivos. Y también no queremos abrumar a las personas con demasiados errores porque realmente no les gusta eso. Y también algo más sobre las reglas. Cumplen diferentes objetivos, ¿verdad? Entonces, algunas de ellas son para crear consistencia en nuestras APIs. Necesitamos los valores de enumeración en mayúsculas porque queremos que los valores de enumeración se vean todos iguales. Y luego hay otras reglas que están destinadas a hacerte detener y pensar críticamente sobre tu diseño de esquema. Bien, aquí hay un ejemplo sencillo que es una regla del Linter que prohíbe los términos de interfaz de usuario. Todos sabemos que poner nombres es difícil. Entonces creamos una lista de términos prohibidos de interfaz de usuario como botón, popover, toaster, modal. Y nos aseguramos de que no aparezcan en los nombres de tipo, campo o argumento de entrada. Así que echemos un vistazo a nuestro tipo de producto aquí. La mayoría de los campos se ven bien. El problema aquí es que en realidad no queremos un campo llamado URL para modal. Y eso se debe a que es posible que el front-end quiera mostrar esto en otro tipo de diseño de interfaz de usuario en el futuro, ¿verdad? Y luego, si de repente es una URL para botón, ¿vamos a cambiar el nombre a URL para botón? Probablemente no. Entonces, en realidad no es una preocupación del back-end si esta URL se muestra en un modal o un botón o cualquier otra cosa. Y ahí está nuestra útil advertencia del Linter. También intentamos ser un poco inteligentes con esto. Tenemos una lista configurable de términos prohibidos como botón, pero también tenemos una lista permitida en caso de que haya una razón válida por la que un esquema necesite usar un término de nuestra lista prohibida en su diseño de esquema. Bien, ese fue un ejemplo bastante trivial, pero hablemos de uno más interesante. Esta es la regla del Linter de prefijo de campo común. En el mal ejemplo, que está a la izquierda, tenemos tres campos en nuestro tipo de tienda que comparten el prefijo de zona horaria. Entonces tenemos abreviatura de zona horaria, desplazamiento de zona horaria, minuto de desplazamiento de zona horaria. Y eso es una indicación bastante clara de que estos campos podrían agruparse en un tipo propio. Y eso es lo que hacemos en el buen ejemplo. Creamos un tipo de zona horaria. Entonces, la tienda tiene un campo llamado zona horaria de tipo zona horaria y el tipo de zona horaria tiene abreviatura, desplazamiento y minutos de desplazamiento en él. Y esta regla del Linter realmente solo pretende empujarte y hacerte pensar si nos falta un tipo de objeto aquí. ¿Debería haber un objeto de zona horaria? Y es un aviso porque creo que este probablemente tiene la mayoría de los falsos positivos. Esta regla del Linter es en realidad directamente de nuestro tutorial de diseño de GraphQL disponible públicamente. Ese es el enlace. Y nuestro tutorial de diseño se publicó en 2018 después de que el equipo adquirió algo de experiencia y formó algunas opiniones sólidas sobre el diseño de APIs de GraphQL. Ha crecido y evolucionado con el tiempo, incluidas traducciones increíbles de personas de la comunidad. Y la actualización más reciente se realizó hace aproximadamente un mes y medio. Todavía estamos iterando activamente en él. El tutorial de diseño presenta una lista de 23 reglas de diseño y luego utiliza el ejemplo de construir una API relacionada con el comercio para trabajar en ellas porque eso es lo que sabemos. Veamos cómo el tutorial de diseño expresa un sentimiento sobre el subobjeto. He resaltado algunas partes en verde. Realmente solo está reiterando lo que dijimos. Debes crear un nuevo tipo que agrupe todos los campos estrechamente relacionados y tu tipo no necesita tener un gran, es decir, no necesita tener un equivalente directo en el modelo. Y me gusta eso porque es una gran extensión de la regla número dos, que es nunca exponer detalles de implementación en el diseño de tu API. Bien, dado que hay dos fallas de violación del Linter relacionadas con los campos de retorno de mutación, creo que vale la pena profundizar en ellas también. Suponiendo que un esquema de GraphQL tenga una mutación de creación de producto, que no estoy mostrando. Aquí está el esquema para la carga útil asociada. Entonces puedes ver aquí que nuestra carga útil devuelve dos campos, un nombre de producto y una matriz de errores. Por lo tanto, no tiene mucho sentido tener errores de nivel superior para fallas de usuario. Por lo tanto, los incluimos como parte de la respuesta. Y luego requerimos que las mutaciones devuelvan un campo de errores, que internamente llamamos errores de usuario, cuyo tipo implementa una interfaz de error. Y luego el tipo de campo de errores debe ser una lista no nula de objetos no nulos. Y la interfaz de error debe implementar una cadena no nula para el mensaje de error del usuario final y luego una lista de cadenas no nulas para la ruta del campo de error. Y luego el tipo de campo de errores también puede devolver, lo siento, también debe devolver un campo de código que es una enumeración nula. Aquí tienes un ejemplo de respuesta. Entonces, a la izquierda puedes ver una respuesta para una mutación exitosa. Devuelve una lista vacía para errores y devuelve el nombre del producto recién creado para el campo de nombre del producto. Y luego una mutación fallida devolvería uno o más objetos de error y luego nulo para el nombre del producto. Puedes ver que nuestro código de error aquí es inválido, que no es el más útil, pero entiendes la idea.

19. Automatización de la Revisión de API y Medición de la Calidad

Short description:

El bot de esquema de GraphQL ha sido una herramienta valiosa para hacer cumplir las reglas de diseño de API y proporcionar un linting automático del esquema. Al mover el proceso de linting al principio del proceso de desarrollo, los equipos pueden validar el diseño de su API a medida que lo construyen. Shopify ha dejado de revisar las solicitudes de extracción debido al aumento en su número y la carga de trabajo de soporte. En su lugar, brindan soporte en tiempo real a través de Slack y Discourse y revisan las solicitudes de extracción cuando se etiquetan explícitamente. El equipo también se reúne semanalmente para compartir aprendizajes e identificar tendencias en el desarrollo de API. La automatización de la revisión del diseño de implementación con RuboCop es el siguiente paso, y la medición de la calidad de la API es un desafío en curso.

De acuerdo, volviendo a esto, si lo volvemos a analizar, podemos ver en la línea dos que el tipo de retorno del nombre del producto se enumera como no nulo. Eso en realidad causaría una violación del linting, ya que requerimos que todos los tipos de retorno de mutación sean nulos. Somos muy estrictos con nuestros tipos de retorno de mutación. Podemos ver las reglas correspondientes en el tutorial de diseño de GraphQL que inspiró esta regla de linting. Puedes ver la regla número 22, la mutación debe proporcionar errores a nivel de negocio del usuario a través de un campo de errores de usuario en la carga útil de la mutación. La entrada de error de consulta de nivel superior está reservada para errores a nivel de cliente y servidor. Y luego la regla número 23 en la parte inferior, la mayoría de los campos de carga útil para una mutación deben ser nulos a menos que realmente haya un valor para devolver en cada posible caso de error. Esa es un poco difícil de pronunciar. Nuestro tutorial de diseño es genial, pero también es bastante largo. Por lo tanto, tener el linting automático del esquema es una forma muy útil de recordar a las personas algunas de las ideas allí.

Así que construimos nuestro bot de esquema de GraphQL para que sea extensible y hemos realizado algunos cambios con el tiempo. Mencioné antes que la lista de reglas de linting se ha ampliado. También hemos extraído la funcionalidad principal de linting en una gema interna. Por lo tanto, esa gema contiene una interfaz de línea de comandos que las personas pueden ejecutar desde su entorno de desarrollo para realizar el linting localmente. Nos dimos cuenta de que estábamos agregando fricción al proceso de desarrollo al ser una barrera de último minuto para enviar solicitudes de extracción. Y a las personas no les gusta escuchar que su diseño de API debe cambiar cuando sienten que ya están listos para enviarlo. Al mover la capacidad de hacer linting de sus esquemas antes en el proceso de desarrollo, pueden validar el diseño de su API a medida que construyen su API o pueden construir una API primero, lo cual es aún mejor. Aquí puedes ver que son exactamente las mismas violaciones de linting que acabamos de ver, pero en formato de línea de comandos. Estoy realmente emocionado con lo sólida que es nuestra herramienta de linting y cuánto ha mejorado la rotación de ATC de nuestro equipo. Pero a medida que Shopify continuó creciendo, la cantidad de solicitudes de extracción también aumentó. Incluso sin la distracción de comentar todas las cosas pequeñas, todavía no podíamos manejar la carga de trabajo de soporte. Así que en junio de este año, hicimos algo realmente loco. Dejamos de revisar las solicitudes de extracción por completo. Para contextualizar esto para ti, estábamos tratando de revisar cientos de solicitudes de extracción a la semana como un trabajo a tiempo parcial para una persona. Por lo tanto, los números simplemente no tenían sentido para nosotros. Con nuestro enfoque de no revisión, estamos viendo menos solicitudes de extracción, gracias a Dios, pero aún estamos manteniendo un pulso sobre las API de GraphQL que se están desarrollando a través de otras formas. Todavía estamos trabajando con los equipos individualmente en la fase de diseño técnico. Eso es antes de que comiencen a construir sus API o cualquier funcionalidad subyacente. Brindamos soporte en tiempo real a través de Slack y Discourse. Intentamos aprovechar Discourse tanto como sea posible para que las conversaciones estén documentadas y sean fácilmente consultables cuando las personas buscan respuestas. Y revisamos con gusto las solicitudes de extracción cuando los equipos nos etiquetan explícitamente para una revisión. Cuando nos reunimos como equipo semanalmente, brindamos un espacio para que todos compartan los aprendizajes de las discusiones que han tenido con personas de otros equipos. Esto nos ayuda a identificar tendencias en cómo los equipos están construyendo APIs. Nos ayuda a identificar nuevos espacios problemáticos. Y también es un gran mecanismo para compartir contexto. Mirando hacia atrás en todo este viaje, creo que probablemente esperamos demasiado tiempo para comenzar a automatizar. Nos preocupaba la calidad de las APIs si nos alejábamos, pero no nos dimos cuenta de que la calidad de nuestras revisiones de solicitudes de extracción podría estar disminuyendo de todos modos. Recientemente descubrimos otra área que podemos automatizar y estamos trabajando activamente en ello ahora. Estamos utilizando RuboCop para detectar problemas en el código Ruby que son invisibles para el esquema. Mencioné anteriormente que nos enfocamos en revisar el diseño del esquema, el diseño de implementación y el diseño de características cuando hacíamos las revisiones de código. Automatizamos la revisión del diseño del esquema con el bot de esquema de GraphQL en nuestra aplicación. Ahora estamos automatizando la revisión del diseño de implementación con RuboCop, lo cual es genial. También hablé un poco sobre la preocupación por la disminución de la calidad de la API, pero para ser honesto, descubrir cómo medir la calidad de nuestras APIs es un problema completamente nuevo. Me encantaría hablar más sobre esto. Claramente puedo hablar de ello durante un tiempo también. Así que avísame si tienes alguna pregunta y gracias por escuchar.

QnA

Sesión de Preguntas y Respuestas y Manejo de Directivas

Short description:

Gracias a todos nuestros ponentes por una sesión fantástica. Ahora tomaremos un descanso de 10 minutos antes de comenzar la sesión de preguntas y respuestas. Si tienen alguna pregunta, siéntanse libres de escribirla en el chat o levantar la mano en Zoom. Rebecca será la moderadora de la sesión de preguntas y respuestas. Una pregunta del chat fue sobre cómo manejar múltiples contextos con la directiva de contexto. El ponente explicó que eligieron mostrar una sola experiencia en la API de la Tienda y utilizaron campos en la API de Administración para manejar diferentes vistas de gestión. Los valores predeterminados de las directivas se pueden manejar en el esquema o en el código. Las desventajas de usar directivas incluyen la falta inicial de soporte de bibliotecas y posibles errores de caché. Sin embargo, la depuración ha sido relativamente sencilla debido al manejo anticipado de casos excepcionales.

De acuerdo, muchas gracias, Rebecca. Gracias a todos nuestros ponentes, eso fue fantástico. A todos los participantes que aún están aquí, gracias por acompañarnos. Todavía nos queda una hora, vamos a tomar un descanso de 10 minutos. Tomemos un descanso, beban agua, respiren, levántense de sus asientos, den un paseo de unos cinco minutos y luego nos encontramos aquí de nuevo en punto de la hora, creo que en exactamente 10 minutos. Y luego comenzaremos nuestra sesión de preguntas y respuestas durante una hora completa. Todos nuestros ponentes están aquí, incluido Gui, quien dará una charla relámpago la próxima semana durante la conferencia en sí los días 9 y 10. Así que nuevamente, si tienen preguntas, siéntanse libres de escribirlas en el chat. De lo contrario, también pueden levantar la mano aquí en Zoom. Estaré atento a eso y les pediremos que hagan su pregunta en vivo a cualquiera de los ponentes que esté presente aquí. Así que déjenme ver, ¿estamos listos? Entonces Jonathan, Alex, Lana, Theo, Greg, Rebecca, Guy y yo le cederé el control a Rebecca durante la próxima hora. Ella acaba de dar una charla final. Ella también será la moderadora de la sesión de preguntas y respuestas. Así que Rebecca, te toca a ti. Sí, si alguien tiene preguntas, escríbanlas en el chat, también estaremos atentos a cualquier mano levantada y los llamaremos al escenario para que hagan su pregunta en vivo. Te cedo la palabra, Rebecca. Genial, gracias. Así que vamos a tratar de no saltar demasiado entre temas porque hablamos de muchas cosas muy diferentes. Creo que tiene sentido comenzar con las directivas porque sé que hubo mucho interés en eso. Entonces, Alexander, comenzaré con tu primera pregunta del chat, que fue, para la directiva de contexto, ¿cómo manejas el caso en el que se necesitan múltiples contextos al mismo tiempo? Por ejemplo, una vista general de gestión de precios en diferentes países. Y esto es para Alex o Lana si está aquí. Sí, simplemente voy a responder. Me encanta esta pregunta. La razón por la que elegimos las directivas es precisamente porque no queríamos exponer este comportamiento. Uno de nuestros requisitos en la API de la Tienda era que solo queríamos mostrar una sola experiencia. Por lo tanto, no queríamos abrir la posibilidad de consultar diferentes países y valores de precios para una vista de gestión. Pero también es importante tener en cuenta que una de las razones por las que nos encanta GraphQL es que no es una solución única para todo. En Shopify, también tenemos otra API de GraphQL llamada API de Administración. Y aquí es donde realizamos todo nuestro comportamiento de gestión. Recientemente lanzamos un nuevo campo para manejar precios contextuales llamado Precios Contextuales. Y en lugar de usar directivas, estamos utilizando campos aquí precisamente por esa razón, donde queremos usar alias para decir, hey, dame todos los precios para el país de Francia. Y luego, en otro alias, dame todos los precios para el país de Italia. Y nuevamente, evaluamos nuestra solución en función de los casos de uso. Para el caso de mostrar todo a la vez, queríamos usar una directiva de consulta de nivel superior. Para el caso de mostrar diferentes vistas de gestión, usamos campos. Por lo tanto, no teníamos esa necesidad de una solución única para todo. Por lo tanto, utilizamos diferentes herramientas. ¿Eso responde a tu pregunta o hay algo que pueda aclarar? No, está absolutamente claro. Genial. OK. Algunas otras preguntas sobre las directivas. No creo que realmente hayamos hablado sobre cómo se manejan los valores predeterminados. Eso podría ser interesante. Obviamente, creo que Greg habló un poco sobre la compatibilidad con versiones anteriores. Teo también, este es un tema importante para nosotros. Entonces, ¿cómo te aseguras de no romper nada en términos de compatibilidad con versiones anteriores? Sí. Se me ocurren dos formas de manejar los valores predeterminados para las directivas. Lo primero es que, nuevamente, una de las razones por las que elegimos usar una directiva en nuestro caso es que está definida en el esquema. Por lo tanto, puedes definir valores predeterminados y puedes ser muy explícito incluso si es obligatorio, por ejemplo, y no quieres proporcionar un valor predeterminado. Debido a que estamos utilizando GraphQL, podemos hacer esas distinciones y podemos obligar a los clientes de la API a comportarse de esa manera. Pero luego, por supuesto, digamos que no hiciste eso o querías recurrir a un comportamiento predeterminado, como si no incluyeras la directiva en absoluto, la segunda forma de manejar los valores predeterminados sería en el código. En nuestro caso, si no se proporciona ningún país en el código, simplemente volvemos al comportamiento predeterminado y tenemos una forma de manejarlo. Así que creo que es un enfoque de dos frentes, primero, puedes asegurarte de que tu esquema sea explícito para manejar los valores predeterminados o puedes hacer que tu código también tenga un respaldo para esto. Genial, eso es muy útil. Gracias. La última pregunta sobre las directivas, creo que está en la mente de todos, es ¿cuáles son las desventajas de usar directivas y cómo se manifiesta eso, supongo también en la depuración? Sí, creo que hay varias formas de responder a esto. En primer lugar, una de las desventajas que tuvimos al usar directivas es que al principio no era completamente compatible con la biblioteca. Por lo tanto, no necesariamente es compatible con todas las herramientas, pero una de las ventajas de construir esto es que pudimos contribuir a las gemas de Ruby de GraphQL para crear el mundo que queríamos ver. Construir ese soporte fue un desafío, pero esperamos que otros se beneficien de ello. Otra desventaja es que, por ejemplo, podrías experimentar errores si tienes caché. Por lo tanto, debes asegurarte de estar pensando en cualquier argumento que se esté enviando y ser consciente de que cualquier capa de caché se invalida. Y luego, la tercera cosa es en términos de depuración, preguntaste si tuvimos muchos desafíos en realidad porque lo definimos en nuestro esquema. Nuevamente, estamos obteniendo un argumento de código de país válido, lo estamos haciendo obligatorio. Por lo tanto, estamos manejando todos esos casos excepcionales desde el principio. Por lo tanto, no tenemos un caso en el que estemos creando un estado inválido. Por lo tanto, en cuanto a la depuración, ha sido bastante bueno. En realidad, simplemente ha sido lograr que todo el soporte funcione en nuestras diferentes bibliotecas lo que ha sido el mayor desafío y desventaja.

Teo sobre División de Consultas y Directivas

Short description:

La complejidad de dividir consultas en múltiples consultas manualmente, sin herramientas de automatización, se debe a la necesidad de identificar los puntos finales problemáticos y confiar en las mediciones de rendimiento. Aunque existe una popular biblioteca de GraphQL para Flutter, la mejor biblioteca para el desarrollo de aplicaciones Flutter depende de necesidades específicas. Si ya está en producción, construir una biblioteca personalizada puede ser el enfoque recomendado. Además, permitir que las directivas se apliquen antes en la especificación del lenguaje GraphQL podría ayudar a abordar los puntos problemáticos de los cambios de esquema y la validación de campos para clientes móviles.

Pero también, como dije antes, con la pregunta anterior no es un enfoque de talla única para todos. Así que funcionó para este caso, pero no funcionará para todos los casos. Genial. Gracias.

Antes de continuar, Jonathan o Greg, ¿tienen algo... Siento que ambos tienen opiniones muy fuertes sobre las directivas. ¿Hay algo que quieran agregar o podemos seguir adelante? No tengo nada específico sobre las directivas. De acuerdo. Genial. Volveré a ustedes cuando hablemos sobre la nulidad porque sé que ambos tienen mucho más que decir al respecto. De acuerdo. Así que pasemos a Teo. Solo un recordatorio para todos. Teo estaba hablando sobre consultas de alto rendimiento para clientes móviles. Teo, esta pregunta también es de Alexander. ¿La división de fragmentos en una sola consulta en múltiples consultas se hace manualmente o creaste una herramienta para automatizar esto? Muy buena pregunta. Gracias por las preguntas Alexander. Realmente apreciamos tu perspectiva. Sí, se hace manualmente. Diría que principalmente por algunas razones. La primera es que necesitamos poder identificar qué punto final está teniendo problemas internamente. Por lo tanto, esta también es una buena opción para una consulta separada, que no es algo que necesariamente puedas hacer con una herramienta del lado del cliente. Y también depende en gran medida de las mediciones de performance. Como dónde te encuentras en comparación con los umbrales. Nuevamente, creo que es un poco demasiado complejo para encapsularlo en una herramienta en este momento. Pero esto sería realmente bueno, creo, a medida que construimos con lenguajes más grandes en móviles, como Kotlin, Swift y React Native. Creo que esto se convertiría en una característica muy útil para los desarrolladores de GraphQL. Así que, en resumen, es demasiado complejo en este momento, pero sí, espero con ansias esto. Siéntete libre de contactarme. Diría que si quieres trabajar en esto juntos. Genial. Sí, esperaba que fuera demasiado complejo, pero quiero decir, tienes un gran equipo allí, así que quién sabe qué han creado, así que. De acuerdo, la siguiente pregunta para Teo es de Santosh. Disculpa si pronuncio mal el nombre. ¿Cuál podría ser la mejor biblioteca de GraphQL para el desarrollo de aplicaciones Flutter? Honestamente, no tengo idea. No he trabajado mucho con Flutter. Aunque, entre el momento en que hiciste la pregunta y ahora, investigué un poco al respecto. Parece haber una biblioteca de GraphQL para Flutter, que es bastante popular. Sí, simplemente busca en el portal de Flutter por GraphQL guión bajo Flutter. La encontrarás. Parece tener una buena calificación. Quiero decir que la respuesta a esta pregunta probablemente depende de tus necesidades. Y si solo estás probando GraphQL, entonces sí, elige algo simple. Así puedes tener una opinión al respecto. Pero si esto es para algo que ya tienes en producción y estás buscando cambiar, creo que lo mejor es construir tu propia biblioteca. Principalmente porque las que he visto, nuevamente, con mi tiempo limitado, no generan modelos. Entonces, tal vez esto es algo que te gustaría hacer. Parece que inyectar consultas de GraphQL a través de variables de cadena es fácilmente rompible. Así que sí, recomendaría invertir. Si esto es algo en lo que estás interesado en llevar a una escala más grande, entonces definitivamente invierte en ello y probablemente crea tu propia biblioteca. Genial, impresionante.

Vamos a pasar a otra pregunta de Alexander con todas las preguntas de hoy. También para Teo, en la discusión sobre omitir e incluir versus consultas duplicadas. ¿Se resolverían los problemas con cualquier cambio de campo si las directivas se pudieran ejecutar antes de validar un campo? Esto permitiría que omitir ignore el campo y no lo rompa si no existe en el esquema. Alexander, ¿hay algo que quieras decir para elaborar más sobre eso? Siento que todo sonaba extraño al salir de mi boca, pero entiendo lo que estás tratando de decir. No, creo que lo hiciste bien, no, es, creo que mi interpretación de por qué las directivas no funcionaron en el escenario, fue que las directivas, si recuerdo correctamente, se aplican después de que se validan todos los campos. Por lo tanto, no puedes aplicar una directiva de omitir a un campo que no está en el esquema del servidor, lo que significa que no puedes usarla para protegerte contra cambios de esquema. Entonces supongo que, ¿podría ser tal vez una propuesta para la especificación del lenguaje graphQL, encontrar alguna manera de permitir que las directivas se apliquen antes para resolver este problema, para que puedas decir que el cliente puede decir como, no me importa si ya no está, como si lo ignoraras y fingieras que solicité esto sin los campos, como lo harías si el esquema fuera válido? Sí, creo que es una buena pregunta. Sí, definitivamente es el sueño para los clientes móviles. Siento que esto aportaría mucho valor a los móviles, no tanto para la web porque siempre puedes corregirlo directamente, pero es bueno asegurarse de que este campo sea inmune a los cambios. Bueno, si no existe, se mueve o algo así, se convierte en deuda técnica en lugar de apagar incendios. Entonces, sí, esto es, creo que el mayor punto problemático para los móviles con GraphQL en este momento, especialmente en aplicaciones grandes. Como hemos experimentado en Shopify. Así que sí, espero que Omitir e Incluir pueda convertirse en algo más que solo introducir nuevas capacidades y mejorar el rendimiento sino también protegerse contra cambios potenciales. Nuevamente, no creo que esto sea lo que los creadores de GraphQL tenían en mente. Tal vez no sea la solución adecuada tampoco. Es una buena pregunta. Siento que nos beneficiaríamos si no cambian Omitir e Incluir, entonces podríamos beneficiarnos de algo similar a, okay, estoy tratando de consultar este campo pero por favor, antes de ejecutarlo y resolver la consulta déjalo a un lado si ya no existe.

Cambios en el Envío y Disponibilidad de Campos

Short description:

Estamos a punto de realizar cambios e introducir nuevos campos en la pantalla de pedidos, que se utiliza mucho. Aunque sería valioso tener una función que prediga los costos de las consultas, es poco probable que suceda debido al uso actual. Estamos trabajando en construir un único frontend para diferentes configuraciones de API, lo cual requiere determinar si un campo está disponible y si la función está habilitada.

Creo que esto sería muy valioso para nosotros. Siempre es estresante cuando realizamos cambios. En este momento es lo que estamos a punto de hacer. Con una de las funciones, organizaremos una versión beta para los comerciantes sobre la nueva función. Y estamos a punto de introducir nuevos campos justo entre la temporada de BFCM y las vacaciones en la pantalla de pedidos, que es la pantalla más utilizada probablemente, creo, alrededor de unos 1,500,000,000 al mes en este momento. Así que sí, es estresante y sería mucho mejor si pudiéramos beneficiarnos de dicha mejora. Para responder a tu pregunta, es poco probable que suceda, creo, debido a la forma en que se está utilizando actualmente. Pero siempre podemos soñar y luchar por ello. Sí, sería una función que también me encantaría ver. Estamos tratando de construir un único frontend para diferentes configuraciones de implementación de una API de GraphQL. Por lo tanto, uno de los problemas que tenemos que resolver es determinar si el campo estará allí, si la función está habilitada en el servidor en esta versión de la API. Es una función que también me gustaría ver.

Predicción de Costos de Consulta y Campos Obsoletos

Short description:

En Shopify, utilizamos los costos de consulta solicitados y reales para predecir y determinar la complejidad y el rendimiento de las consultas. Calculamos el costo potencial en función del número de campos y su complejidad. Para monitorear el rendimiento de las consultas, lo seguimos en producción y verificamos los informes regularmente. Las consultas paralelas deben revisarse en función del seguimiento del rendimiento, la implementación de nuevos campos y los cambios en los umbrales. Tenemos un panel de control de salud de la API para que los socios detecten posibles cambios disruptivos y brindemos alertas y plazos para la adaptación. El bot del esquema de GraphQL ayuda a detectar cambios disruptivos y proporcionamos registros de cambios y alertas proactivas a los socios. Los campos obsoletos se marcan pero no se eliminan para facilitar la migración entre versiones del esquema.

De acuerdo, genial. Un par de preguntas más generales, Tao, sobre tu charla. Hablaste sobre la fase de implementación de tu API, hablaste sobre el costo de la consulta. ¿Qué estás utilizando para predecir los costos de las consultas? Entonces, específicamente en Shopify, tenemos dos cosas que se llaman costos de consulta solicitados y costos de consulta reales. El solicitado es la complejidad, es una simple operación matemática basada en el número de campos que estás consultando y su complejidad. Por ejemplo, si estás solicitando una página de 50 elementos en la que cada elemento tiene tres o cuatro campos, haces 50 veces tres o cuatro, eso te da una idea de cuál podría ser el costo potencial como máximo si todo lo que estás solicitando se devolviera y el costo de la consulta real es lo que realmente cuesta en realidad. Mientras ejecutamos esto en nuestro entorno local de GraphQL, ya podemos predecir si esto es un buen candidato, por ejemplo, para una consulta paralela. Eso es lo que usamos internamente, pero también me gustaría saber, qué están utilizando actualmente las personas que asisten a esta llamada o más adelante, si desean comunicarse para determinar eso. Sí, si alguien tiene algo que esté utilizando y quiere compartirlo en el chat, está bien. De hecho, voy a darle un momento a Gui para que hable aquí porque Gui, siento que escribiste una publicación de blog de ingeniería al respecto que también está disponible públicamente. Sí, exactamente, publiqué una publicación de blog en el blog de ingeniería de Shopify exactamente sobre cómo calculamos el costo de la consulta. Sí, básicamente, el GLDR es, tenemos un costo de consulta predicho y un costo de consulta adicional. Por ejemplo, si solicitas una página de 50 registros, pero solo devuelve dos. Entonces, el costo pasa de 50 a dos. También hay algunas formas diferentes en las que tratamos los escalares y también las mutaciones y todo. Y al final tenemos una correlación lineal entre el costo de la consulta, el costo de la consulta adicional y el tiempo de respuesta del servidor. Tengo un gráfico en esta publicación de blog al final. Así que podemos correlacionar. Así que podemos tener una correlación bastante lineal entre ellos. Así que sí. Echa un vistazo a esta publicación de blog, explica cómo calculamos y cómo se correlaciona con el tiempo de respuesta del servidor. Genial. Y acabo de compartir un enlace en el chat a la publicación de blog para que todos puedan leerla y obtener más información. Última pregunta para Teo sobre las consultas paralelas. ¿Con qué frecuencia deben revisarse para una pantalla en particular? Entonces, si tienes una instrumentación sólida y estás rastreando el rendimiento de tu consulta en producción, entonces se vuelve más fácil, diría que sí, probablemente revisa el informe una vez al día para algo crítico, solo para tener una idea de cuándo el rendimiento está disminuyendo. En su mayoría, puedes alinearlo con la implementación de nuevos campos, medir el rendimiento, pero idealmente eso se debe hacer antes de implementar algo nuevo en producción. Solo anticipando una posible disminución y ver si hay margen para una mejora también. De vez en cuando, si sientes que esto ya no se adecua a nuestros umbrales o si estás cambiando los umbrales porque tienes metas más agresivas, eso es lo que está sucediendo en Shopify Mobile. Pasamos de que sea satisfactorio que se cargue en dos segundos a ahora estamos apuntando a 0.5. Entonces tenemos que redefinir eso y sí, eso también significa revisar con frecuencia lo que estamos haciendo y monitorear. Tenemos un panel de control completo con las pantallas más importantes clasificadas según cuántas veces se ven y tenemos una puntuación más o menos que se basa en el promedio diario, creo y un promedio de tres meses por cliente en iOS y Android. Entonces sí, estar atento a eso y hasta donde sé, sí, surge al menos una vez por semana en la mesa para pantallas específicas. Genial, eso es increíble. De acuerdo, creo que nos alejaremos un poco de lo móvil. Tenemos dos preguntas en el chat de Dominic. La primera es para cualquier persona que pueda tener experiencia con esto. ¿Alguien ha utilizado un GraphCDN? ¿Alguien tiene opiniones o experiencia al respecto? De acuerdo, parece que tal vez ninguno de nosotros haya jugado con eso pero siento que todos están a punto de hacer clic en el enlace que compartiste y echarle un vistazo y formar algunas opiniones. Así que, publiquen en el canal, en el chat si tienen algún comentario al respecto. Esta próxima pregunta también de Dominic es bastante compleja, así que se la voy a dar a Guy para que comience, pero Jonathan, creo que también tendrás mucho que decir al respecto. Entonces, la pregunta es, ¿alguna vez eliminan consultas obsoletas? ¿Cómo abordan la evolución del esquema como el patrón de nombre de consulta B2 o B3? Y en el contexto de eliminar consultas, ¿cómo monitorean el uso? Así que, esto es mucho. Sí, es mucho. Sí, hasta ahora, eliminar campos obsoletos. Hasta ahora o tal vez hasta los próximos días, no tenemos versiones para los tipos de retorno en los campos, por ejemplo. Entonces, a veces tendremos como money V2, money V3, y eventualmente necesitaremos eliminar el money original. Así es como funciona ahora. Dejar obsoleto esto no es un gran problema debido a la forma en que funciona nuestro sistema de versiones. Entonces tenemos nuevas versiones cada trimestre. Y probablemente la versión inestable ya no tendrá el campo money y pasará a ser una versión candidata. Y en este momento, la versión candidata es 2022.01. Y cuando se lanza 22.01 automáticamente, esto se convierte en la nueva versión estable. Las solicitudes de versiones antiguas obsoletas, por ejemplo, si haces una solicitud para 2019.04, en realidad devuelve una respuesta en 2021.01, creo, como la versión más antigua disponible. Incluso si no estás, si estás, como, retrasado, como, esta ventana de versiones disponibles, de versiones, siempre está en movimiento. Entonces, eventualmente puede romperse si no prestas atención. Pero ahora podemos versionar los campos devueltos con la nueva versión de Ruby, GraphQL, GM. Entonces, no tendremos una órbita virtual, con suerte para la próxima, para las próximas aplicaciones. Luego, ¿cómo nos aseguramos de no romper nada? Entonces hay muchas piezas en movimiento y diferentes equipos trabajando en esto. Primero, tenemos el bot del esquema de GraphQL. Entonces, básicamente, detecta cuando tenemos un cambio disruptivo y eliminar un campo es un cambio disruptivo. Entonces, lo que significa, si el desarrollador recibe una alerta al respecto, si es intencional, está bien, puedes proceder. Y cuando se lanza, cuando el cambio va a la versión candidata cualquier socio que desarrolle aplicaciones para Shopify, tienen un panel de control de salud de la API donde detecta si las consultas actuales que están realizando se romperán en el futuro. Entonces, ahora la versión candidata actual ya no tiene este campo, por lo que detecta si tu aplicación se romperá en una versión futura, por lo que comenzamos a recibir algunas alertas al respecto y también se te da un plazo, por ejemplo. Esto está próximo en la próxima versión. Entonces, si deseas obtener la última versión estable, tal vez tengas tres meses para adaptarte, o si siempre estás utilizando la versión más antigua disponible, tienes más tiempo, por lo que tienes un panel de control claro con elementos reales claros para mantenerte actualizado y también todo el equipo de defensa de socios trabaja en registros de cambios para cada versión de lanzamiento, por lo que puedes estar atento a esos registros de cambios para nuevas versiones. De cualquier manera, puedes verificar los registros de cambios, pero estamos alertando proactivamente a los socios sobre próximos cambios disruptivos. Genial, sí. Entonces había mucho en la pregunta, había mucho en esa respuesta. Jonathan, ¿hay áreas en las que quieras profundizar más? Claro, esto es algo en lo que personalmente me estoy enfocando mucho recientemente con la API de la tienda. Tradicionalmente, hemos sido muy, no sé cuál es la palabra, pero indulgentes con las aplicaciones donde marcaremos un campo como obsoleto, pero no lo eliminaremos, aunque tenemos versiones de la API simplemente porque queremos que las personas tengan facilidad para migrar entre versiones del esquema. En un mundo ideal, eso sería genial porque las personas verían campos obsoletos y dejarían de usarlos.

Manejo de Campos Obsoletos y Nulabilidad

Short description:

Estamos planeando ser más agresivos en la eliminación de campos obsoletos debido al gran código base que tenemos. Los problemas de nomenclatura V2 y V3 fueron causados por una limitación en nuestro proceso de versionado, que ahora está solucionado. Seguimos el uso de campos específicos a través de informes de salud de la API y paneles internos para informar nuestras decisiones. Los campos obsoletos pueden ser desafiantes de manejar y estamos explorando formas de mejorar el proceso. Es importante tener en cuenta que no hay una solución única para el versionado de APIs. Comunicamos los cambios próximos a los desarrolladores y brindamos recordatorios más cercanos a las fechas. Las uniones de entrada no son preferidas en lugar de la solución actual. La nulabilidad ha sido un tema de discusión y tenemos experiencia con ella en arquitecturas de gráficos distribuidos.

En realidad, lamentablemente, ese no es el caso. Tenemos muchos desarrolladores que simplemente los ignoran. Con el tiempo, nuestro código base se ha vuelto tan grande, como dijimos, tenemos 5,000 tipos y muchos esquemas, que no es factible mantener estos campos obsoletos para siempre. Debido a que tenemos APIs versionadas y esquemas versionados como dijo Guy, pronto comenzaremos a ser un poco más agresivos en la eliminación de campos obsoletos por esa razón.

En cuanto a los problemas de nomenclatura V2 y V3, eso fue, como dijo Guy, debido a una limitación que teníamos en nuestro proceso de versionado, que ahora está solucionado. Esperemos que eso nunca vuelva a suceder, porque francamente son feos y muy confusos. ¿Cuál debo usar? Price V2, V3, pero estoy usando la versión de enero del esquema, pero estoy usando V2, es un desastre, ¿verdad? A todos nos encanta tener APIs agradables con nombres adecuados y somos muy obsesivos con que las cosas sean consistentes. Por lo tanto, eliminar las V2 y V3 es algo que definitivamente queremos hacer.

Tienes una pregunta sobre el seguimiento del uso, de la cual hablamos un poco, que es nuestro informe de salud de la API que ven los socios. Pero también internamente, tenemos paneles que podemos consultar y decir, ¿cuántos clientes están utilizando este campo específico? Eso lo utilizamos mucho para informar nuestras decisiones sobre cuándo podemos obsoleto un campo. Si está obsoleto, ¿qué tan agresivos podemos ser al eliminarlo en una versión futura? Si este campo es muy, muy popular, aunque esté obsoleto, tal vez nos preguntemos por qué es tan popular. ¿El nuevo campo no está haciendo lo que se supone que debe hacer, o no es mejor de lo que habíamos anticipado? No sé si hay alguna herramienta de código abierto para hacer esto. Sé que tenemos una gema de código abierto llamada GraphQL Metrics, que rastrea más cosas sobre los tiempos de ejecución de los resolutores y demás, pero internamente, tenemos herramientas que enumeran cada consulta que llega, y básicamente hacemos un recuento de cada campo solicitado y lo agregamos. Todo eso va a un panel detrás de escena que podemos usar para determinar cuándo pueden desaparecer las cosas. Pero sí, los campos obsoletos, sinceramente, son geniales, pero también pueden ser bastante problemáticos de manejar. Así que estamos buscando formas de mejorar eso. Me encantaría escuchar los pensamientos de otras personas al respecto. Sé que también ha habido discusiones en la especificación de GraphQL sobre los argumentos, porque creo que los argumentos actualmente no se pueden marcar como obsoletos, lo cual está integrado en la especificación, lo cual es interesante. Así que también hemos tenido que hacer algunos trabajos al respecto. Sí, creo que hay mucho trabajo por hacer en este espacio en general, en cuanto al versionado de APIs y los cambios disruptivos, y cómo hacerlos menos dolorosos, especialmente para los clientes móviles, como dijo Tila, porque en los dispositivos móviles, una vez que la aplicación está ahí fuera, técnicamente no puedes obligarlos a actualizar. Quiero decir, puedes hacerlo, pero no es la mejor experiencia de usuario, ¿verdad? Así que esto es algo en lo que todos debemos pensar. Sí, definitivamente hay margen para la innovación en este espacio. Sí.

También agregaré que, obviamente, decimos que odiamos cuando los campos son como money v2, money v3, o como money v7, porque se siente bastante mal. Al mismo tiempo, creo que si tu API es mucho más pequeña, fue un esfuerzo realmente grande para nosotros implementar un sistema de versionado de API, ¿verdad? Entonces, no creo que tener un par de campos v2 sea lo peor. También diré que obviamente tienes que seguir el proceso de hacer un campo v2, hacer que todos tus clientes lo utilicen, luego deshacerte de tu campo antiguo o cambiar tu campo antiguo y luego migrarlos de nuevo al campo de dinero original, ¿verdad? Así que creo que siempre es un proceso largo deshacerse de esas v2 y v3 en tu código base. Pero creo que puedes hacerlo como un proceso más fácil sin implementar un sistema completo de versionado. No sé, esos son mis pensamientos. ¿Todos están de acuerdo o en desacuerdo? ¿Es malo y no deberíamos permitir que nadie lo haga? Sí. Tienes que trabajar dentro de las limitaciones de tu sistema, supongo. Sí, creo que Alice lo dijo perfectamente antes. No hay una solución única para todos. Somos un poco afortunados porque el generador de Ruby GraphQL que tenemos admite muchas cosas que utilizamos para el versionado. Y parte de eso ha sido un proceso colaborativo, pero si estás ejecutando un backend de nodo o algo así, es posible que las herramientas que tienes disponibles sean diferentes. Entonces, esto es solo lo que ha funcionado para nosotros, pero no hay una solución única para todos. Oh, de acuerdo. Vamos a pasar a Greg. ¿Puedo interrumpir con una pregunta de seguimiento? Adelante. ¿Haces un seguimiento de qué aplicaciones solicitan los campos obsoletos para poder enviar mensajes específicos, como, `oye, tu aplicación todavía está utilizando un campo antiguo`? Sí. El último enlace que compartí en el chat es nuestro informe de salud de la API. Entonces, para eso, es como un socio. Para nosotros, el socio es un desarrollador de aplicaciones de terceros. Por lo tanto, estamos rastreando todo por aplicaciones para que un desarrollador de aplicaciones pueda ingresar y decir, oh, estoy utilizando estos campos. Y estos campos se eliminarán o cambiarán en funcionalidad dentro de tres versiones a partir de ahora. Y a medida que nos acercamos, le damos mucho pensamiento al plan de comunicación para esto, del cual no tengo un enlace exacto, pero puedes leer sobre ello en el sitio web de shopify.dev. A medida que nos acercamos a las fechas, enviamos correos electrónicos masivos solo para recordar a las personas que se acerca. Porque puedes decirle a alguien que, hey, este campo desaparecerá en un año y no piensan que es algo que deben solucionar con urgencia. Por lo tanto, necesitan ese recordatorio de 30 días o lo que sea, solo para refrescar su memoria. Jonathan, ¿quieres agregar algo? Lo siento. No, dijiste exactamente lo que iba a decir. Lo que ibas a decir, de acuerdo, genial. Lo siento. De acuerdo, Greg, esta es una pregunta para ti, pero luego la abriremos como una pregunta para todos. Si las uniones de entrada existieran hoy, ¿las usarías en lugar de tu solución actual de one of? Interesante pregunta. Supongo que diría que no todavía. Las uniones de entrada han generado, siento que, mucho entusiasmo acerca de ellas. Y siempre son como la solución que falta y que estamos a un paso de resolver y este problema se resolverá con la unión de entrada. Y he escuchado eso tantas veces y luego descubrir que realmente esta solución de one of es la que resuelve el problema y lo resuelve mejor que cualquier cosa que la unión de entrada pueda hacer, porque la unión de entrada no podría hacer nada más allá de ser un conjunto de objetos de entrada que uno puede juntar y recibir. Y lo que tenemos hoy en día que podemos hacer con una validación simple del lado del servidor puede permitirnos ingresar escalares o listas o cualquier otra cosa. Y simplemente se adapta a muchos más casos de uso y ni siquiera es muy difícil de hacer. Así que sí, estoy firmemente del lado de que no necesitamos necesariamente esta especificación y espero que no se implemente. Genial, gracias por compartir tus opiniones algo sesgadas sobre las uniones de entrada. Esto es... Siéntete libre de proporcionar el contraargumento. No, no siento que pueda hacerlo. Básicamente me has convencido. Estoy en el equipo de one of... Entonces, Greg, esta es una pregunta para ti, pero luego la abriremos como una pregunta para todos. ¿Cuándo te has visto atrapado por las restricciones de no nulidad? Sumergámonos en la nulabilidad. Oh, Dios, la nulabilidad. Tengo una larga historia con la nulabilidad y comenzó desde... Mi experiencia previa a Shopify, estaba trabajando en arquitecturas de gráficos distribuidos.

Desafíos de Federación y Nulabilidad

Short description:

La federación y la nulabilidad plantean desafíos en las arquitecturas de GraphQL. Si bien una arquitectura monolítica de GraphQL reduce los problemas de simetría, los problemas de sincronización de objetos y el cumplimiento fallido aún persisten.

Entonces, básicamente, haciendo gráficos federados. Y la federación es interesante porque vas y tienes... No puedes asumir que un objeto siempre existe en singularidad porque en realidad es una composición de muchos objetos provenientes de muchos lugares y de repente te desincronizas con este objeto que existe en un lugar pero no en el otro lugar y luego hemos garantizado que obtendrás el objeto excepto que proviene de dos lugares. Y luego uno de ellos no pudo cumplir y luego todo se desmorona. Y fue una introducción difícil al hecho de que, wow, la nulabilidad es realmente una promesa exagerada en muchos casos y hay muchas razones por las que estas cosas pueden fallar. Así que en realidad esto es una de las cosas que encontré que fue sorprendentemente simple sobre lo único que fue sorprendentemente simple al venir a Shopify fue llegar y decir, wow, tenemos un monolito que hace una arquitectura de GraphQL. Así que solo estamos hablando con un servicio y eso realmente disminuye muchos de los problemas de simetría que tienes en algo como una arquitectura federada. Y sin embargo, los mismos tipos de problemas aún existen. E intenté tocar un poco eso en mi charla.

Nulabilidad y Sistema de Versionamiento de Shopify

Short description:

La nulabilidad en GraphQL puede ser un tema desafiante, pero es importante encontrar un equilibrio. Si bien los campos no nulos facilitan las cosas para los clientes, hay casos en los que la nulabilidad es necesaria. El sistema de versionamiento de Shopify permite transiciones más suaves y los cambios disruptivos pueden ser opcionales para los clientes. El sentido común juega un papel importante en la determinación de la nulabilidad, y si un campo tiene una restricción de base de datos, debe ser no nulo. La implementación de Shopify también cuenta con un sólido sistema de versionamiento que simplifica los cambios en la API y genera esquemas diferentes para diferentes versiones.

MetaFields ha sido realmente interesante de analizar en el contexto de GraphQL porque los metadatos, estas extensiones de datos personalizadas, están fundamentalmente en desacuerdo con lo que GraphQL intenta hacer. GraphQL es una estructura rígida y fuertemente tipada. Sabemos lo que te estamos presentando. Y con estas extensiones de metadatos que estamos construyendo, estamos creando algo que es ortogonal a lo que GraphQL te proporciona. Te ofrecemos estructuras flexibles para que puedas definir tu propio esquema y diseñar tu propia cosa y luego obtenerlas a través de esta única interfaz estática. Y así encontramos que la nulabilidad se ha convertido en algo muy importante allí. A veces funciona directamente en nuestra contra y deseamos que haya algunos campos que podamos consultar. Y hay otros lugares donde funciona de alguna manera por accidente para nosotros. Algunas cosas, como dar referencias nulas, que era parte del diseño original del sistema, ahora también acomodan el hecho de que no siempre podemos cumplir con la conexión. Y tenemos suerte de que esta cosa fuera nula desde el principio. Así que definitivamente estamos siendo más proactivos al pensar en qué necesitará hacer este campo en dos años y si realmente podemos garantizar los datos para ello. Me encantaría escuchar las opiniones de otros desarrolladores sobre esto. Estoy esperando a que Jonathan desmutee. La nulabilidad ha sido un tema en el pasado. Es una de las razones por las que tenemos algunos de los campos v2 que tenemos. Por ejemplo, creo que en nuestra API de Strawford, creo que eran los artículos. Cada artículo tiene un autor, y el autor era no nulo. Resulta que eso no siempre es cierto. Ahora tenemos el autor v2 que es, devuelve el mismo modelo de objeto que antes, solo que es no nulo. Este es definitivamente un problema con el que nos hemos encontrado antes. Me encantaría decir que siempre deberías devolver nulo, o lo siento, siempre no nulo, y todo funcionaría. Pero eso realmente es un problema para los clientes. Así que es realmente un acto de equilibrio. Es interesante en el lado de Metafield, estamos realmente interesados en el equipo de Jonathan, y con gran anticipación de lo que ustedes tienen en proceso, porque realmente están desbloqueando algo crítico para nosotros en términos de, en este momento tenemos esta idea de que si queremos usar la API actual y construir sobre ella, vamos a tener que entrar en un contrato de esquema realmente incómodo, donde, ya sabes, requerimos este campo y luego tal vez una entrada secundaria, que es una personalización de la entrada principal. Sabes, tenemos que hacer estos patrones porque esta cosa es nula y no podemos desanularla. Y sabes, si fuera simplemente... Bueno, lo que ustedes están trabajando es realmente una gran oportunidad para nosotros. Y realmente nos da muchas razones para comprometernos potencialmente con firmas de API extrañas, como firmas de argumentos, con el valor que ustedes están haciendo nos da la capacidad de transicionar la API de una manera muy metódica y fluida. Entonces, tal vez vamos a tener un estado extraño durante una versión de la API, pero en dos versiones a partir de ahora, si podemos ajustar la nulabilidad de los argumentos, podríamos convertir esto en una interfaz mucho más limpia y concisa a largo plazo. Ese es el objetivo. Para dar más contexto sobre lo que Greg está hablando, creo que Guy mencionó anteriormente que había algunas cosas que no podíamos versionar de manera efectiva dentro de nuestra estrategia. Una de ellas era el tipo de campo que devuelve, otra es el nombre de un argumento, qué toma el argumento, como objetos de entrada, y la nulabilidad. Cambiar la nulabilidad de un campo es algo que no pudimos versionar por razones técnicas detrás de escena, estamos corrigiendo todo eso, por lo que básicamente estamos haciendo que nuestro sistema de versionamiento sea mucho más poderoso para permitirnos realizar estos cambios disruptivos de una manera más agradable y fluida. Ese autor v2 no tendría que existir. Literalmente, si solicitas la versión A, no es nulo, si solicitas la versión B en el futuro, de repente es nulo. Es un cambio disruptivo, seamos claros, estos son cambios disruptivos, pero debido a que tenemos el versionamiento en su lugar, no es un cambio disruptivo inmediato, es un cambio disruptivo opcional por parte del cliente. Estás optando por esta nueva versión, lo que significa que vienen todos los cambios disruptivos con ella, pero al menos ahora tenemos la oportunidad de hacer esos cambios disruptivos de una manera agradable. También diré que algunos de los oradores, Yi, creo que alguien más también habló sobre el versionamiento de la API, y el hecho de que tenemos esta versión inestable, creo que Greg también lo mencionó, estos cambios van a nuestra versión inestable antes de que realmente se programen para la versión candidata de lanzamiento. Entonces, a veces cuando tus funciones o nuevos campos están en la versión inestable, ese es un buen momento para tratar de definir la nulabilidad. Esto es lo que estoy escuchando, tal vez hay esta idea de que las cosas deberían ser en su mayoría nulas y luego las corregiremos para que no sean nulas o estás diciendo que las cosas deberían ser no nulas si creemos que deberían ser nulas y si eso no funciona, las cambiaremos en el futuro? ¿Cuál es el patrón aquí? Creo que, supongo que esto va dirigido a mí. Creo que la respuesta es que muchas de ellas se reducen al sentido común, como un producto siempre debería tener un precio, ¿verdad? Así que eso debería ser simplemente no nulo. Creo que este cambio nos permite en la oportunidad o en la situación en la que surge algún caso extremo aleatorio, no estamos limitados por el hecho de que, bueno, ahora tenemos que crear un nuevo campo y cambiar la semántica de lo que significa este campo, ahora podemos hacerlo nulo en una versión futura y las cosas aún tienen sentido semántico. Esa fue la cosa más importante, como, tenemos estos nombres de campo, nos tomamos tanto tiempo y cuidado para nombrarlos de la manera que queremos nombrarlos. Y ahora decimos, bueno, ahora tenemos que encontrar un nuevo nombre solo porque nos equivocamos en la nulabilidad, ¿verdad? Como, y por eso existe V2 es porque todavía queremos llamarlo autor, solo que V2. Así que creo que Greg lo expresó bastante bien en sus comentarios, como sentido común. Si hay una restricción de base de datos que dice que debe ser no nulo, probablemente deberíamos hacer que el campo sea no nulo. Y si obtenemos un nulo en algún lugar de la lógica del resolvedor, tenemos un problema, ¿verdad? Así que sí, es difícil. Todavía me inclinaría hacia no nulo cuando sea posible solo porque facilita mucho las cosas para los clientes. No tienen que tener una declaración if que diga si esto no existe. No tienen que tener un estado separado, como todo un estado en la interfaz de usuario. ¿Qué sucede si esto es nulo? Simplemente hace las cosas más fáciles para todos. Genial, de acuerdo. Creo que las preguntas de seguimiento definitivamente en el chat o podemos conectarnos fuera de línea porque este es todo un gran tema. Voy a hacer otra pregunta, tal vez para Guy, veamos. Tal vez puedas mencionar algunas de las cosas que son únicas de la implementación de GraphQL de Shopify. De acuerdo. Déjame pensar. Creo que nuestro sistema de versionamiento es algo muy importante. Entonces, aunque le faltaban cosas como el tipo de retorno para los campos, era más una imitación, como una imitación a bajo nivel en la gema. Pero creo que el sistema de versionamiento es realmente bueno. Y no solo significa que genera esquemas diferentes para diferentes versiones. Pero básicamente lo que hacemos, cada vez que hacemos un cambio en la API, algo sustancial, básicamente tenemos un archivo IML con todos los cambios de la API. Y básicamente podemos decir, okay, este cambio de API tiene lugar en la versión estable. Entonces, cuando declaras un campo, podemos decir, okay, este campo depende de este cambio de API. Entonces, cuando estés listo para lanzar de inestable a la versión RC, solo necesitas cambiar este archivo IML. No necesitas revisar todos tus nuevos campos o nuevos cambios y mutaciones y hacer cambios en el código. Es más como cambios de configuración. Así que es muy fácil de lanzar, aunque tenemos todo este versionamiento y este tipo de cambio de API también es utilizado por otros equipos, por ejemplo, para detectar cuándo una función pasa de inestable a la fecha de lanzamiento. Entonces, significa que es hora de escribir un DevChangelogPost.

Rendimiento y Caché en GraphQL

Short description:

Más uno no son la única preocupación de rendimiento en GraphQL. La sobrecarga de analizar, validar y analizar consultas también puede afectar el rendimiento. Los esquemas complejos y los analizadores computacionalmente pesados ofrecen oportunidades de optimización. La caché puede ser desafiante, especialmente con directivas como en el contexto. La validación estática de la caché y considerar el equilibrio entre precisión y velocidad son consideraciones continuas. Alexander, un ingeniero principal de front-end, compartió su experiencia con los esfuerzos de construcción de API y su charla relámpago sobre PHP.

También tiene algunas implicaciones en las comunicaciones. Y también cuando realizamos algún cambio en la API en nuestra versión de lanzamiento, comienza a generar advertencias para los socios. Entonces, el sistema de versionamiento tiene muchas implicaciones con las comunicaciones, con nuestro código base, con data. Así que creo que eso es muy, muy único, sí. Genial, ahora voy a pasarle la palabra a Greg para hablar sobre algo más. No sé si es único o no. No sé qué pasa en otras empresas.

Greg, hablaste de que tenemos esquemas públicos y luego esquemas internos. ¿Quieres hablar sobre tal vez qué se incluye en nuestros esquemas privados que no son públicos o por qué tenemos ambos? Sí, claro. A principios de este año estuve trabajando en la función de mercados que ahora está en acceso temprano. Ahora se está implementando lentamente para los comerciantes. Estamos agregando peso a eso. Y lo interesante de esto es que es un modelo completo y en realidad, tenemos que hacer un rellenado completo. Requiere mucha configuración que tenías dispersa en tu tienda antes. Y luego reescribimos toda esa configuración y este nuevo modelo de data. Y estamos eliminando piezas de diferentes partes del administrador y luego consolidando esto alrededor de este nuevo portal que hace todo lo que implica vender globalmente en un solo lugar. Y por eso no necesariamente lanzaríamos una API pública de inmediato porque todavía hay muchas piezas que están en proceso. Y algunos de los comentarios más perspicaces que recibimos son realmente cuando lanzamos la función al público y comenzamos a tener algunos de nuestros comerciantes que la usan, realmente obtenemos algunos consejos inmediatos sobre qué ajustar, esto debe ir aquí, solo algunas cosas que podríamos haber pasado por alto o simplemente oportunidades que nos gustaría aprovechar en el MVP final que lanzamos. Dicho esto, simplemente tener todo en ejecución en la versión inestable que usamos internamente nos permite lanzar una de estas funciones y hacer que las personas la usen dentro del contexto del administrador. Y una vez que hayamos llevado la función al punto en que es una función pública lista para su lanzamiento y la vamos a hacer headless, de repente se puede agregar a una de las versiones de esquema y los consumidores externos pueden comenzar a controlarla realmente. Y luego eso también la abre al ecosistema de aplicaciones, que es un punto clave. Mientras estamos desarrollando internamente, los desarrolladores de aplicaciones no pueden innovar necesariamente en esta función. Y tan pronto como esté disponible, la API, cualquier persona puede escribir una aplicación que comience a construir sobre esto para administrar tu tienda o cualquier otra cosa. Genial. Gracias por explicarlo. Nos estamos quedando sin tiempo. No hablamos mucho sobre M plus uno o el rendimiento, excepto desde la perspectiva móvil en esta parte de preguntas y respuestas. Entonces, Jonathan, ¿qué hay de M plus uno? ¿Son la única causa de problemas de rendimiento? ¿Hay otras causas? ¿Qué más? Sí. Sí. En resumen, no son la única preocupación de rendimiento. Creo que son los más obvios porque cuando ocurren, son bastante drásticos porque obviamente, si solicitas 50 productos por ejemplo, y un campo es nuestro producto porque hay una iteración o cálculo muy costoso detrás de escena. Es bastante lineal, sin embargo, creo que lineal es la palabra correcta. Es bastante obvio que aquí hay un problema de rendimiento. Pero definitivamente hay otros casos donde el rendimiento puede ser un poco lento. Una de las cosas únicas de GraphQL es que debido a que hay un esquema, debido a que hay seguridad de tipo y otras cosas en su lugar hay una sobrecarga completa que ocurre en cada consulta. Entonces, cuando nuestro back-end recibe una consulta tiene que analizarla, tiene que permitirla, tiene que validarla. Y luego hay ciertos análisis que tenemos encima, como el costo, la consulta, el cálculo, todas esas cosas. Entonces, si tu esquema es particularmente complejo o tienes un analizador que hace algo extremadamente pesado en cada consulta, como que eso es una gran oportunidad para la optimización. O bien, no tiene que ser un M plus uno. Un campo puede ser simplemente, simplemente muy costoso de calcular. Alex mencionó esto antes con las directivas y la caché. Una de las cosas con la directiva en el contexto de la que tuvimos que ser muy conscientes es que como está en la parte superior de la consulta, hacer una caché de estilo de muñeca rusa de subconsultas en esa consulta se vuelve muy imposible porque el nivel superior ahora está cambiando. Entonces, una de las cosas que estábamos considerando con la directiva en el contexto era para comprar en línea y luego recoger en la tienda, queremos poder contextualizar y decir, los resultados de inventario de ubicación deben ordenarse según la distancia a tu ubicación, ¿verdad? Porque eso es una característica de usuario muy agradable. Bueno, el problema es que si en esa directiva de repente aceptamos dos valores de punto flotante muy precisos, ¿verdad? Básicamente, toda la consulta se almacena en caché en esa única ubicación por 10 decimales. Entonces, lo que decidimos hacer fue en lugar de tomar ubicaciones discretas, tomaríamos una ID de todas nuestras ubicaciones conocidas, que es una tienda del comerciante. Lo que luego diría, está bien, puedes darnos tu ubicación preferida y luego ordenaremos todo en función de eso. Eso es una gran ventaja en términos de capacidad de caché. Entonces, los M plus uno definitivamente no son lo único que puede perjudicarte mucho, pero son uno de los más obvios. ¿Eso responde a tu pregunta? Sí, no, creo que eso es tal vez, no hablamos mucho sobre la caché fuera de que Alex lo mencionó durante su charla. Creo que en nuestro lado, estamos explorando, tal vez podamos almacenar en caché también algunas de las validaciones estáticas, ¿verdad? No solo la ejecución de la consulta de GraphQL, sino todas esas cosas que mencionó que suceden antes. Algunas de esas cosas podrían ser caché. Teo, estoy seguro de que estás tratando de almacenar en caché tanto como sea posible en los clientes móviles. Sí. También es complicado porque en algunas partes de los comerciantes valoran la precisión sobre la velocidad, es decir, cuando se cumplen los pedidos, solo quieren asegurarse de tener la lista más actualizada. En caso de que se haya editado un pedido, esto sucede principalmente entre las personas que están detrás del escritorio realizando ediciones de pedidos y las personas que están en el almacén cumpliendo pedidos. Entonces, en este caso, por ejemplo, desactivamos la caché para que siempre tengas la información más actualizada en otras partes de la aplicación, especialmente al tratar con medios y videos. Sí, esto es algo que realmente no podemos permitirnos, así que almacenamos en caché tanto como sea posible. Genial, sí. Dominik, veo tu pregunta en el chat solo sobre la optimización del rendimiento y la documentación, lo siento, la caché de documentos, creo que hemos insinuado eso un poco, pero nos estamos quedando sin tiempo, así que en realidad voy a devolverle a Marcia para que nos termine. Muy bien, fantástico. Gran trabajo Rebecca, fue una gran moderación. Y a todos los que han participado, Dominik, Alexander, realmente lo apreciamos. Alexander, veo que tu cámara está encendida y has quitado el silencio, no sé si quieres saludar, simplemente decirnos qué haces, si te sientes cómodo haciendo eso y luego comenzaré. Sí, claro. Soy Alexander, mi título es ingeniero principal de front-end con OpenSocial, pero también he estado liderando nuestros esfuerzos de construcción de API. De hecho, hice una pequeña charla relámpago que se transmitirá la próxima semana y estaré en el panel de lenguajes que no son JavaScript. Así que hablando sobre PHP, que tiene sus propios desafíos interesantes. Muy bien, fantástico, gracias por eso, gracias por participar. Dominique y todos los demás que han estado aquí durante las últimas tres horas. Es mucho tiempo, pero has estado con nosotros.

Conclusión y Agradecimiento

Short description:

Gracias Jonathan, Alex, Lana, Athel, Greg, Rebecca y Andy por abordar los desafiantes problemas de GraphQL que enfrentamos en Shopify y compartir cómo el equipo los está enfrentando. Es importante discutir problemas, no solo aspectos destacados. La grabación será compartida por Git Nation y las charlas pregrabadas se subirán al canal de YouTube de Shopify. Gracias a todos los participantes y al equipo de Git Nation por aceptar este formato de masterclass único. Nos lo pasamos muy bien y apreciamos la participación de todos.

Realmente les agradecemos. Muchas gracias. Jonathan, Alex y Lana, Athel, Greg, Rebecca, definitivamente Andy, muchas gracias por ayudarnos a enfrentar algunos de los difíciles problemas de GraphQL que experimentamos aquí en Shopify y cómo el equipo está abordando esos problemas. Creo que no es frecuente que las personas hablen de problemas, las personas solo hablan de los aspectos destacados. Así que esto fue realmente genial. Muchas gracias por organizar todo esto.

Esta grabación se compartirá y distribuirá más adelante por Git Nation y nuestro equipo aquí en Shopify también subirá las cinco charlas pregrabadas al canal de YouTube de Shopify. Así que pueden buscarlas allí. Y a todos los que han participado. Una vez más, muchas gracias. Lara y su equipo en Git Nation. Gracias por aceptar esta forma no tan normal de realizar la masterclass. Nos divertimos con esto. Esperamos que nuestros participantes también lo hayan disfrutado. Sí, muchas gracias por todo su tiempo, a todos. Lo apreciamos de verdad. Bueno, cuídense, cuidense y nos vemos la próxima vez.

Watch more workshops on topic

GraphQL Galaxy 2021GraphQL Galaxy 2021
140 min
Build with SvelteKit and GraphQL
Top Content
Featured WorkshopFree
Have you ever thought about building something that doesn't require a lot of boilerplate with a tiny bundle size? In this workshop, Scott Spence will go from hello world to covering routing and using endpoints in SvelteKit. You'll set up a backend GraphQL API then use GraphQL queries with SvelteKit to display the GraphQL API data. You'll build a fast secure project that uses SvelteKit's features, then deploy it as a fully static site. This course is for the Svelte curious who haven't had extensive experience with SvelteKit and want a deeper understanding of how to use it in practical applications.

Table of contents:
- Kick-off and Svelte introduction
- Initialise frontend project
- Tour of the SvelteKit skeleton project
- Configure backend project
- Query Data with GraphQL
- Fetching data to the frontend with GraphQL
- Styling
- Svelte directives
- Routing in SvelteKit
- Endpoints in SvelteKit
- Deploying to Netlify
- Navigation
- Mutations in GraphCMS
- Sending GraphQL Mutations via SvelteKit
- Q&A
React Summit 2023React Summit 2023
145 min
React at Scale with Nx
Featured WorkshopFree
We're going to be using Nx and some its plugins to accelerate the development of this app.
Some of the things you'll learn:- Generating a pristine Nx workspace- Generating frontend React apps and backend APIs inside your workspace, with pre-configured proxies- Creating shared libs for re-using code- Generating new routed components with all the routes pre-configured by Nx and ready to go- How to organize code in a monorepo- Easily move libs around your folder structure- Creating Storybook stories and e2e Cypress tests for your components
Table of contents: - Lab 1 - Generate an empty workspace- Lab 2 - Generate a React app- Lab 3 - Executors- Lab 3.1 - Migrations- Lab 4 - Generate a component lib- Lab 5 - Generate a utility lib- Lab 6 - Generate a route lib- Lab 7 - Add an Express API- Lab 8 - Displaying a full game in the routed game-detail component- Lab 9 - Generate a type lib that the API and frontend can share- Lab 10 - Generate Storybook stories for the shared ui component- Lab 11 - E2E test the shared component
React Advanced Conference 2022React Advanced Conference 2022
95 min
End-To-End Type Safety with React, GraphQL & Prisma
Featured WorkshopFree
In this workshop, you will get a first-hand look at what end-to-end type safety is and why it is important. To accomplish this, you’ll be building a GraphQL API using modern, relevant tools which will be consumed by a React client.
Prerequisites: - Node.js installed on your machine (12.2.X / 14.X)- It is recommended (but not required) to use VS Code for the practical tasks- An IDE installed (VSCode recommended)- (Good to have)*A basic understanding of Node.js, React, and TypeScript
GraphQL Galaxy 2022GraphQL Galaxy 2022
112 min
GraphQL for React Developers
Featured Workshop
There are many advantages to using GraphQL as a datasource for frontend development, compared to REST APIs. We developers in example need to write a lot of imperative code to retrieve data to display in our applications and handle state. With GraphQL you cannot only decrease the amount of code needed around data fetching and state-management you'll also get increased flexibility, better performance and most of all an improved developer experience. In this workshop you'll learn how GraphQL can improve your work as a frontend developer and how to handle GraphQL in your frontend React application.
React Summit 2022React Summit 2022
173 min
Build a Headless WordPress App with Next.js and WPGraphQL
Top Content
WorkshopFree
In this workshop, you’ll learn how to build a Next.js app that uses Apollo Client to fetch data from a headless WordPress backend and use it to render the pages of your app. You’ll learn when you should consider a headless WordPress architecture, how to turn a WordPress backend into a GraphQL server, how to compose queries using the GraphiQL IDE, how to colocate GraphQL fragments with your components, and more.
GraphQL Galaxy 2020GraphQL Galaxy 2020
106 min
Relational Database Modeling for GraphQL
Top Content
WorkshopFree
In this workshop we'll dig deeper into data modeling. We'll start with a discussion about various database types and how they map to GraphQL. Once that groundwork is laid out, the focus will shift to specific types of databases and how to build data models that work best for GraphQL within various scenarios.
Table of contentsPart 1 - Hour 1      a. Relational Database Data Modeling      b. Comparing Relational and NoSQL Databases      c. GraphQL with the Database in mindPart 2 - Hour 2      a. Designing Relational Data Models      b. Relationship, Building MultijoinsTables      c. GraphQL & Relational Data Modeling Query Complexities
Prerequisites      a. Data modeling tool. The trainer will be using dbdiagram      b. Postgres, albeit no need to install this locally, as I'll be using a Postgres Dicker image, from Docker Hub for all examples      c. Hasura

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

GraphQL Galaxy 2021GraphQL Galaxy 2021
32 min
From GraphQL Zero to GraphQL Hero with RedwoodJS
Top Content
We all love GraphQL, but it can be daunting to get a server up and running and keep your code organized, maintainable, and testable over the long term. No more! Come watch as I go from an empty directory to a fully fledged GraphQL API in minutes flat. Plus, see how easy it is to use and create directives to clean up your code even more. You're gonna love GraphQL even more once you make things Redwood Easy!
Vue.js London Live 2021Vue.js London Live 2021
24 min
Local State and Server Cache: Finding a Balance
Top Content
How many times did you implement the same flow in your application: check, if data is already fetched from the server, if yes - render the data, if not - fetch this data and then render it? I think I've done it more than ten times myself and I've seen the question about this flow more than fifty times. Unfortunately, our go-to state management library, Vuex, doesn't provide any solution for this.For GraphQL-based application, there was an alternative to use Apollo client that provided tools for working with the cache. But what if you use REST? Luckily, now we have a Vue alternative to a react-query library that provides a nice solution for working with server cache. In this talk, I will explain the distinction between local application state and local server cache and do some live coding to show how to work with the latter.
TechLead Conference 2023TechLead Conference 2023
35 min
A Framework for Managing Technical Debt
Let’s face it: technical debt is inevitable and rewriting your code every 6 months is not an option. Refactoring is a complex topic that doesn't have a one-size-fits-all solution. Frontend applications are particularly sensitive because of frequent requirements and user flows changes. New abstractions, updated patterns and cleaning up those old functions - it all sounds great on paper, but it often fails in practice: todos accumulate, tickets end up rotting in the backlog and legacy code crops up in every corner of your codebase. So a process of continuous refactoring is the only weapon you have against tech debt.In the past three years, I’ve been exploring different strategies and processes for refactoring code. In this talk I will describe the key components of a framework for tackling refactoring and I will share some of the learnings accumulated along the way. Hopefully, this will help you in your quest of improving the code quality of your codebases.

React Summit 2023React Summit 2023
24 min
Debugging JS
As developers, we spend much of our time debugging apps - often code we didn't even write. Sadly, few developers have ever been taught how to approach debugging - it's something most of us learn through painful experience.  The good news is you _can_ learn how to debug effectively, and there's several key techniques and tools you can use for debugging JS and React apps.
React Summit 2023React Summit 2023
26 min
Principles for Scaling Frontend Application Development
After spending over a decade at Google, and now as the CTO of Vercel, Malte Ubl is no stranger to being responsible for a team’s software infrastructure. However, being in charge of defining how people write software, and in turn, building the infrastructure that they’re using to write said software, presents significant challenges. This presentation by Malte Ubl will uncover the guiding principles to leading a large software infrastructure.
React Advanced Conference 2022React Advanced Conference 2022
22 min
Monolith to Micro-Frontends
Top Content
Many companies worldwide are considering adopting Micro-Frontends to improve business agility and scale, however, there are many unknowns when it comes to what the migration path looks like in practice. In this talk, I will discuss the steps required to successfully migrate a monolithic React Application into a more modular decoupled frontend architecture.