Это письменная версия выступления, которое я недавно читал на GraphQL Conf 2019. Если вы предпочитаете просмотреть видеоверсию, вот она:

Для тех из вас, кто предпочитает читать и хочет получить немного больше информации, вот более подробная версия выступления со ссылками и всем этим забавным. Наслаждаться!

Здесь представлен обзор GraphQL на Coursera, некоторые технические решения, которые мы приняли на раннем этапе, и размышления о влиянии этих решений за последние три года. Я надеюсь, что вы извлечете один или два урока из нашего путешествия и примените их к своей собственной истории GraphQL!

Инженерная организация Coursera использует GraphQL в производстве более трех лет - он поддерживает как наши мобильные клиенты, так и наш веб-клиент, и обслуживает миллионы запросов в день! Но три года назад ландшафт, поддерживающий GraphQL, сильно отличался от сегодняшнего, и некоторые из наиболее очевидных вариантов построения архитектуры GraphQL-системы были гораздо менее очевидными. И когда мы переоценили преимущества GraphQL и то, что он привносит в наш стек, мы подумали, что было бы интересно взглянуть на то, откуда мы пришли, и какие решения выдержали испытание временем (а какие нет). .

Почему мы впервые начали использовать GraphQL

Три года назад Бреннан Саэта и Брайан Кейн пытались найти решение одной из наиболее неприятных проблем, с которыми в то время сталкивалась Coursera: централизация всех REST API, которые наши организация создавалась для простого и легкого потребления. Нам нужна была технология, которая позволила бы клиентам выбирать, какие именно данные им нужны, чтобы мы могли сократить общий набор данных, отправляемых по сети, и GraphQL соответствовал всем требованиям. Посмотрите эту историю здесь и прочтите об этом в блоге Apollo GraphQL здесь.

Подводя итог: наш первый подход к GraphQL очень похож на то, что сегодня называют GraphQL Gateway, тонким сервисом, в котором схема GraphQL и основная бизнес-логика не живут в самом сервисе GraphQL. , но состоят из базовых сервисов. Кроме того, мы выбрали для GraphQL подход сначала данные, что означает, что унифицированная схема GraphQL, предоставляемая нашим шлюзом, была прямым прокси-сервером базовых служб с практически нулевой модификацией базовой службы. график.

Учитывая относительную младенчество экосистемы GraphQL, было ясно, что этот подход является исключением - многие компании в то время выбирали подход сначала схема, в котором схема GraphQL часто была немного изменена. сильно измененная версия их базового графа обслуживания. И довольно часто в этом сервисе GraphQL было много бизнес-логики.

Ключевые решения GraphQL

В ходе оценки технических решений, принятых в прошлом, люди склонны быстро судить о решении в контексте сегодняшнего дня. Когда мы рассматриваем их в том контексте, в котором они были приняты, мы видим, что эти решения были полностью оправданы. Сегодня я делюсь с вами этим контекстом, чтобы вы тоже могли понять, почему мы приняли эти решения. Следующие ключевые решения мы приняли в процессе проектирования нашего решения GraphQL с целью обращения к исходному контексту (проксирование ресурсов REST), а также оптимизации для устойчивого роста нашей схемы GraphQL.

Федерация

В сегодняшней экосистеме GraphQL федерация обычно относится к комбинации объединения запросов и объединения схем, то есть объединенный сервер GraphQL, как правило, представляет собой единую службу GraphQL, которая объединяет несколько Схемы GraphQL вместе и делегирует выполнение соответствующей части графа базовой службе GraphQL.

В то время у нас почти не было словаря, чтобы думать об этом как о федерации, не говоря уже о том, чтобы иметь дело с более чем одной схемой, поэтому наш шлюз технически выполнял только запрос федерации: мы взяли наш собственный язык определения схемы, Мы сами сшили это вместе, и всякий раз, когда запрос GraphQL поступал в службу, мы передавали его в REST.

Генерация схемы в первую очередь кода

Как скажут вам многие энтузиасты GraphQL, есть два лагеря для создания сервера GraphQL: сначала SDL или сначала код, грубо говоря, редактируете ли вы GraphQL SDL для изменения схемы или редактируете что-то еще (код). который в конечном итоге сгенерирован в схему GraphQL.

В Coursera мы уже вложили много времени и усилий в единую структуру REST под названием Naptime, которая дала нам отличное место для начала создания нашей схемы, поэтому в сочетании с замечательным инструментарием, предоставляемым Sangria, мы выбрали чтобы выполнить создание схемы в первую очередь кода.

Схема сшивки

Чтобы полностью реализовать наше видение унифицированного API GraphQL для всех наших конечных точек REST, нам нужно было выяснить, как мы собираемся «сшить» или «скомпоновать» эти конечные точки простым и масштабируемым способом. У нас было много вариантов, включая несколько итераций того, как мы должны назвать поле GraphQL, которое поступает из конкретной конечной точки REST.

В конце концов, мы выбрали ту, которая наиболее точно соответствует нашим конечным точкам REST: пространства имен. Это означало, что для каждой службы, включенной в нашу схему GraphQL, каждая из них занимала корневое поле верхнего уровня, а вложенная иерархия GraphQL соответствовала иерархии наших REST API.

Три года спустя…

После пары раундов финансирования и миллионов и миллионов новых учеников Coursera важно взглянуть на решения, которые мы приняли во имя «роста», чтобы понять, были ли они надежными. Кроме того, мы рассмотрим несколько вещей, которые мы не «решали», но, тем не менее, были важными факторами в нашей истории GraphQL.

Федерация

Использование нами «федерации» путем делегирования сервисных запросов нашим базовым API-интерфейсам REST сделало наш шлюз невероятно тонким - на самом деле настолько тонким, что разработчикам сервисов даже не приходилось думать об этом. С точки зрения времени выполнения, мы смогли поддерживать запросы по всей поверхности нашего API с помощью только одного преобразователя, потому что мы стандартизировали все наши API. В этом случае разработчики сервисов не писали резолверы вообще.

Кроме того, эта стратегия сделала нашу историю владения действительно гладкой. Команды сохранили право собственности на свои отдельные сервисы и не нуждались во взаимодействии со шлюзом GraphQL в целом.

Однако одним большим недостатком технической реализации, лежащей в основе этого, было то, что было довольно сложно предварительно просмотреть входящие изменения, связанные со схемой, которые повлияли на унифицированную схему GraphQL. К сожалению, это означало, что нам приходилось предварительно просматривать изменения, когда они поступали в производство… что было невероятно проблематично. Мы могли бы создать инструменты для предварительного просмотра этого раньше в процессе разработки, но из-за собственной природы шлюза это определенно было нетривиальной проблемой.

Генерация схемы в первую очередь кода

Генерация схемы «сначала код» оказалась эффективным способом достижения нашей первоначальной цели по отражению наших REST API в схеме GraphQL. Как я уже упоминал ранее, это значительно снизило количество усилий, необходимых для участия в нашей унифицированной схеме, и очень мало нужно было изменить в жизни бэкэнд-инженера, чтобы получить автоматическую поддержку GraphQL.

Однако у этого были и свои недостатки. С технической точки зрения было действительно просто добавить что-то новое в схему GraphQL, но у нас никогда не было твердого мнения о том, должны ли эти новые вещи вообще быть в схеме. Опять же, учитывая контекст проекта, это явно не было целью, но после трех лет неограниченного роста наша схема GraphQL трещала по швам: у нас есть более 7000 типов и более 650 корневых типов. Одним из преимуществ GraphQL является возможность обнаружения, но при таком большом количестве сущностей было действительно сложно определить, какие API-интерфейсы уже существуют, а без надлежащего управления схемой эти API-интерфейсы также не были особенно хорошо документированы.

Схема сшивки

Использование подхода пространств имен для сшивания схемы оказалось довольно надежным решением. Эти пространства имен позволили нам даже понять, как можно обрабатывать более 600 различных REST API с практически нулевыми накладными расходами, связанными с конфликтами или обратной совместимостью - если возникнут какие-либо проблемы, можно будет создать новый API, и мы будем обслуживать обе версии для потомков.

Однако когда дело дошло до внесения изменений в поля в соответствии с фактическими требованиями к продукту (например, блокирование полей или изменение типов на более сложные), у нас не было рабочего процесса для эффективной адаптации графика, что определенно вызвало некоторые икоты, когда дело дошло до обслуживания давно работающих клиентов, таких как наши мобильные приложения.

Клиенты GraphQL

В процессе создания сервера GraphQL мы параллельно занимались внедрением на клиенте. Это было неожиданно хорошей особенностью процесса внедрения GraphQL, поскольку скорость разработки функций в основных клиентах, таких как Relay и Apollo, помогла создать действительно надежный опыт разработки для всех разработчиков клиентов.

Наша большая реализация

В процессе переоценки многих технических решений и того, как они повлияли на нашу организацию, мы сделали довольно серьезное осознание, которое полностью изменило наше представление о проблеме. Это стало основополагающим элементом в контексте проблемы, которую мы решали вначале:

Является ли схема "сначала данные" лучшим вариантом использования GraphQL?

В конечном счете, ответ заключается в нюансах: схема, ориентированная на данные, вернула нашу схему в том виде, в котором она есть сегодня, и очень хорошо послужила нам, нашему продукту и нашим ученикам. Однако, по большому счету, мы чувствовали противоречие с некоторыми из основных принципов GraphQL: ориентированность на продукт. Взято прямо из записи блога Введение в GraphQL:

GraphQL без извинений руководствуется требованиями представлений и интерфейсных инженеров, которые их пишут. Мы начинаем с их образа мышления и требований и создаем язык и среду выполнения, необходимые для этого.

Это, в конечном счете, подчеркивает некоторые из наших колебаний и внутреннего конфликта - разработка на основе схемы - один из самых мощных рабочих процессов, поддерживаемых GraphQL, и документация, выступления и сообщения в блогах отражают это. Хотя наша реализация в конечном итоге была ориентирована на данные, самым сложным для понимания было то, что требования продукта едва не соответствовали возможностям API, в результате чего разработчик продукта вернуться к принятию решений, связанных с бизнес-логикой, на клиенте, а не отправлять их обратно на сервер.

Что дальше с GraphQL @ Coursera

Мы поняли, что соответствие передовым практикам в области разработки на основе схем - это то, что нам нужно и нужно в Coursera. Это тяжелое решение - наша схема data-first выполняет задачу, для которой она изначально была поставлена, но обещание GraphQL - нет, и в результате это означает, что мы начинаем с нуля, как выглядит GraphQL. как на Coursera. У нас есть несколько основных принципов, и мы напишем много сообщений в блогах, пока мы будем продвигаться по этому пути.

Когда дело доходит до нашей схемы, мы переключаем наше внимание на оптимизацию качества, а не количества - не все, что нужно для включения в схему GraphQL, и когда это произойдет, мы должны действительно задуматься о том, как это происходит.

Когда инженеры работают вместе друг с другом, GraphQL фактически будет языком, на котором они общаются, наряду с технологиями. Контракты API основаны на схеме и выводятся непосредственно из продуктов, которые они поддерживают, и обе стороны могут работать и встречаться посередине.

И, прежде всего, схема становится объединяющим слоем для всех инженеров. Наш шлюз GraphQL может и должен быть тем, о чем говорят все инженеры, и инструменты и рабочие процессы будут это отражать.

Собираем все вместе

Несмотря на наше верное суждение при создании нашей первой итерации GraphQL, несмотря на прекрасные решения, которые удовлетворяли требованиям проблемы в течение многих лет, несмотря на функции, которые действительно поддерживали рост нашей схемы GraphQL, ни одна из них не учитывала основную эволюцию нашего команда; развивается не график, а команда. Участвовавшие в этом люди расширили свое понимание технологии, чтобы увидеть, как она может лучше удовлетворить наши потребности, и в конечном итоге это привело к тому, что мы сделали другой выбор, чем наши предшественники.

Благодарим Гаго Фриджерио за редактирование этого выступления, Бреннана Саэту и Брайана Кейна за то, что они были движущей силой GraphQL на Coursera, и команду Developer Experience за помощь в управлении будущим GraphQL на Coursera. Если вышеприведенная работа звучит действительно потрясающе, и вы хотите поработать с современным GraphQL, чтобы способствовать будущему образования, приходите работать с нами!