усы2

Стой под стрелой

Поступки и мысли, о которых могу вспомнить не краснея

Previous Entry Поделиться Next Entry
Граф Кю-эль
усы2
tonsky

Интересная штука. В Фейсбуке придумали Virtual DOM. Идея оказалась такой хорошей, что им выдали кредит доверия на его реализацию (React), и там ещё осталось. И теперь, что бы не сказал Фейсбук, все слушают, раскрыв рот. Так Фейсбук закрепился законодателем мод по фронтенд-фреймворкам.

А у Фейсбука идет обычный рабочий процесс. Идеи рождаются, о них рассказывают на конференциях, они умирают. Естественный отбор, как везде. Скажем, было несколько подходов к Flux, все загнулись, но выстрелил Elm, и тогда Фейсбук просто нанял автора порта Elm архитектуры на JavaScript.

И вот они додумались до GraphQL. На всякий случай повторю: успех GraphQL не связан с качеством самой идеи GraphQL. Его успех — следствие кредита доверия, завоеванного еще статьей про Virtual DOM. GraphQL — плохая спецификация. Но люди слушают, потому что считается, что в Фейсбуке понимают про фронтенд. Они не понимают. Они перебирают варианты. GraphQL — просто еще одна флуктуация.

То есть, проблема, которую предполагает решать GraphQL, она правильная и актуальная. REST — штука идиотская, если делать приложения, а не один раз дернуть (вот я, например, еще в 2014-м на него катил бочку). Проблема в том, как GraphQL к ней подошел.

Смотрите. Задача — запросить данные с сервера. Т.е. нужен язык запросов. Что сделали в Фейсбуке? Они посмотрели на самый простой случай. Типа, запросить одну entity. И придумали самый идиотский, непонятно как сериализуемый, птичий язык. Да, это не JSON. Да, основной мотивацией при изобретении формата запроса было, чтобы запрос выглядел похоже на ответ. Не знакомость, не компактность, не простота генерации/парсинга, не простота реализации, не компонуемость (она будет нужна), не теоретическая база какая-нибудь вроде реляционной алгебры. Короче, придумали. А потом посмотрели, какие случаи такой формат не покрывает. Случаи взяли из своей практики. Какие запросы Фейсбук делает, такие случаи и залатали. Как залатали: налепили хаков поверх того, что придумали выше. Ну, типа, давайте мутации описывать тем же языком, что и запросы. Для пагинации давайте придумаем специальный синтаксис. И т.д.

Ладно. Получилось как получилось. Глобальных претензий две.

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

И вторая проблема. Ладно бы, если бы этот слой как-то магически решал проблемы за вас. Так нет, писать GraphQL сервер придется вам самим. Причем, сама спека очень нетривиальная, там всякие интерфейсы, инклюды, кондишны прям в самом языке запросов, серьезно. То есть люди сели, решили: а давайте сделаем вот чтобы реально была simplest possible thing. Ну и наворотили. Возможно, думали слишком много про удобства, а вышло в целом неудобно, потому что слишком много удобств.

Ну ладно язык, тут расчет, что язык за вас распарсит библиотека, если она есть под что вы там пишите. Эликсир? Джава? Ну, молитесь, чтобы работало. Надеюсь, не выйдет как с HTTP, в котором столько разных возможностей, что добрую половину из них веб-серверы in the wild просто не реализуют. Главное, что всё равно потом вам нужно писать эту логику, которая мапит схему вашей БД на иерархический JSON. И она не получается красивая, она получается рекурсивная. Т.е. это всё та же проблема N+1 запросов, только между сервером и БД. А если сам запрос рекурсивный (можно же рекурсивный запрос на GraphQL написать?), можно и N² сделать.

И всем этим люди занимаются только потому, что Фейсбук так сказал. ¯\_(ツ)_/¯

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


  • 1
Да, почему-то "так делают у больших" считается серьёзным аргументом. Причём, среди программистов, людей с повышенной по определению рациональностью.

ну, пока оно туда-сюда на hn с редитом всплывает - это еще не серьезный аргумент.
но, вот, когда сюда уже докатилось - нужно пойти посмотреть же.

Да ладно, мало ли говна создано в природе, не писать же про каждое из них.

Чем плохо таскать данные обычным HTTP POST JSON? В яваскрипте вон родная сериализация. Единственный минус - отсутствие асинхронных оповещений от сервера.

Несмотря на то, что в целом я согласен, непонятно, а что делать-то?

В тех случаях, когда объектная модель подходит для предметной области, GraphQL, в общем-то, много чего даёт -- эдакая объектная модель на "экспорт", с плюс-минус статической типизацией, расширяемостью (с сохранением обратной совместимости), возможностью воткнуть security, с уже существующими реализациями.

Молиться не надо -- берёшь лопату и копаешь где надо. Это как раз не проблема.

P.S. GraphQL начинает иметь смысл, если думать об API, а не о конкретной реализации.

Edited at 2016-11-16 22:23 (UTC)

> GraphQL начинает иметь смысл, если думать об API, а не о конкретной реализации.

Обычно внешнее API как раз всем пофиг какое, хоть REST. Т.е. оно предполагает, что с ним будут интегрироваться, но не делать на нем полноценные приложения. Лишние запросы и оверхед никого не парят.

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

Я не знаю, у кого там какая мотивация пользовать GraphQL и кто там кому в рот заглядывает. Есть проблема, что данные часто нужно получать небольшими срезами, и поменьше заниматься склеиванием всего на UI. Было бы из чего выбирать, можно было бы спорить, что вот Фэйсбук сделали говно, но это говно все растащили к себе, ибо у Фэйсбука репутация. Но выбирать не из чего.

в одно случае вам понадобится 2 поля
в другом три поля

в итоге не закешировать нихуя. или же придется хранить по 100500 разных копий одинаковых данных - тем самым ваша якобы оптимизация сводится на нет.
а когда запрос на 1 набор данных - можно закешировать.
напрягает размер данных? используете бинарный протокол и сжатие.

Edited at 2016-11-17 04:58 (UTC)

Longpoll + Protocol Buffers рулит! Единственный плюс текстовых протоколов - данные можно смотреть в отладчиках браузеров. По мне слишком малый профит, учитывая его стоимость для пользователя


Кстати Virtual DOM придумал Evan Czaplicki если что. Фейсбук всего лишь внедрила это в js

погодь, протокол graphql был еще давно до React, это как был официальный способ общения с фейсбуком по API. Другое дело, когда людям дали спеки и сделали референсную имплеменитацию. Речь про Relay, наверное..

По теме: давно пора перестать думать о коммуникации, как о вызове удаленных процедур в парадигме "запрос-ответ" - это тот самый, нафик не нужный слой абстракции, комфортная надстройка, агрегация, к которой так все за долгое время (царство HTTP) прикипели.

Так если у меня весь софт состоит из вызова одних процедур другими, то почему общение с удаленным сервисом должно по другому выглядеть? Или в какой парадигме предлагается работать?

по-моему graphql это тупо опенсорсинг внутренней тулзы, которая, ну, удовлетворительная но не впечатляет, сравнимо с WSDL примерно.

имхо, идеально - это что-то вроде datomic + attribute-level security, оно же filtered replication. только это безумно, безумно сложно.

даже асинхронная репликация с perfect information (CRDT) сложная, а с фильтрами - еще на порядок сложнее :(

я вот осилил для себя первую (think asynchronous graph database replication), а вторую нет, то есть оно работало даже, но я утонул в коде и отдебажить не смог

но это же не причина отказываться от решения проблемы? )

у эликсира, раз уж ты упомянул его, есть отличный http://absinthe-graphql.org

Я тоже очень удивился отсутствию стандартных реализаций хотя бы под основные платформы. Думаю, что получится как с OData. Библиотека нашла свою область применения, но отсутствие реализаций под что-нибудь кроме .NET не дала ей стать популярной.

(Анонимно)
Здесь в тексте ничего не сказано, но по твиттеру вижу, что нужно пояснение: graphql назван в честь выражения social graph (= фейсбук) и относится к графам примерно как react относится к реактивности, то есть никак вообще.

https://news.ycombinator.com/item?id=10300815

Пиздец. И эти люди учат нас не ковыряться в носу.

>И всем этим люди занимаются только потому, что Фейсбук так сказал
вам не кажется что это какое то примитивное объяснение? чтото в духе заговора рептилоидов :)
Когда то я очень сильно не понимал почему люди так любят реакт и VDOM. Вообще VDOM начинался как история про "change detection это очень сложно давайте сделаем все просто - изменили данные - все перерисовали". Но почему то на сейчас большую часть разработки на реакте на некотрых проектах занимает "как бы обновлять поменьше виртуал дома, да пореже, потому что он тормозит".
То есть мы притащили VDOM чтоб тратить больше памяти но не парится с change detection, но в результате получилось что мы делаем из говна и палок(из сравнения ссылок, мемоизации и евент эмиттера) ту же систему change detection - и она намного более сложная и хрупкая чем если бы мы изначально делали с расчетом на нее. Абстракция протекла ага. Похоже на ситуацию с графкл?
Вообщем я думал что все любят реакт потому что их обманул фейсбук. Но потом понял что просто большая часть проектов с этими проблемами вообще не сталкиваются(многие блин про SCU и shallowCompare никогда не слышали) - и для них реакт решает проблем больше чем создает.
То же самое и графкл - не всем нужны хитрая динамика и подписки с пушами, не всем нужен клиентсайд стейт, не всем нужен сервер на эликсире, не всем нужен клиент на чем nj отличном от реакта. И да компоненты которые делают только один запрос. Многим просто нужно вытянуть за один запрос связанные сущности и все - для этих целей графкл вполне себе подойдет. И он действительно может упрощать все для некотрых проектов(если сущностей много разных, а динамики мало).
Имхо лучше простой критики сразу показывать как можно сделать лучше(например рассказать что язык запросов может быть не строковым, и вообще более адекватным - тот же даталог, возможно рассказать про датаскрипт/датомик). Иначе это просто все выглядит как хейт который рождает только ответный хейт и никакого обсуждения :)
Вообщем я к тому что программистам надо не абсолютизировать свой опыт - если тебе кажется что люди используют фигню возможно у них просто иные задачи, иной опыт.

Re: Заговор фейсбука

мне вот реакт решил проблему композабельности компонент, которые пишутся разными людьми. тупо толковой диагностикой и coding style. этого было достаточно чтобы выбросить все, что было до него, потому что разработка командой стала в разы быстрее.

а то что он шустрее что-то там перерисовывает - да ради бога, и так хватало перформанса, я чего только в жс не лепил

"проблема N+1 запросов"

А что это за проблема?

Во что трансформируется такой запрос?

{ posts { post_id author { user_id name email userpic }}

Если делать наивно, то мы сначала выберем посты (select post_id, author from posts), а потом для каждого поста сделаем select user_id, name, email, userpic where user_id=%. При количестве постов N получим N+1 запрос.

То есть может оно как-то и обходится, но я что-то не представляю, как такой грамотный конструктор запросов написать, чтобы из представления в GraphQL генерировался SQL с джоином. То есть, представляю, но это явно не «каждый разработчик для своей базы будет делать». Потому что это всё должно быть жутко динамическое: автор может быть, может не быть, может еще что-то к тем же постам запрашиваться, может автор в другом контексте дергаться, и т.д.

Part I

Не согласен, успех GraphQL прочно связан именно с идеей, которая за ним стоит. Идея в том, что клиент сам решает, какие данные от сервера ему нужны, а не выбирает из ограниченного количества эндпоинтов, которые реализованы на сервере. С этой идеей и появился GraphQL. Есть может заслуга репутации фейсбука в том, что GraphQL сильно популярнее того же Falcor, но думаю GraphQL в любом случае был бы популярнее чем Falcor, он более доступен широким массам, там сильно больше удобств и упрощений. GraphQL не возник случайно, это решение конкретной проблемы, вот потом его сильно раздули и выглядит он сейчас не так, каким был изначально. См.: https://www.youtube.com/watch?v=Oh5oC98ztvI

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

По этой причине, по причине денормализованного иерархического JSON-а в результате, по причине сырости библиотек для реализации бэкенда, я и написал свою реализацию графового апи: http://hiku.readthedocs.io/en/latest/. Язык запроса – EDN-структура как в Om.Next/Datomic Pull API, результат – нормализованный, с возможностью денормализовать. И изначально решена проблема N+1 запросов, вместо воркэраунда похожего на хак – https://github.com/facebook/dataloader.

Edited at 2016-11-17 15:08 (UTC)

Part II

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

Поддерживать графовое апи на порядок легче, чем рестовое. У фейсбука как была одна версия графа, так и сейчас та же версия графа за несколько лет, при том, что клиентов и их версий уже десятки если не сотни. У нас сразу два графа для двух клиентов, но версий пока не так много. Писать графовое апи тоже на порядок легче чем рестовый. Так что всё это нужно. Вот GitHub пишет новое публичное API на GraphQL, и мы скорее всего если будем писать новое публичное апи, то возьмём GraphQL, т.к. это правда удобно, что для получения данных и их изменения используется один язык и он стандартизирован и это не CRUD, а что-то вроде CQRS. См.: https://www.youtube.com/watch?v=wPPFhcqGcvk

Рекурсивность вообще не проблема, результат настолько рекурсивный, насколько глубока рекурсия в запросе, а запрос такой, какой нужен клиенту, лишнего там не будет. И выполняться это будет не за N², а просто за N (N == глубина рекурсии), а в случае оптимизации запроса или использования кеширующего dataloader – вообще 1.

И всем этим люди занимаются не из-за того, что это модно (хотя за всех говорить не могу), а потому, что пришло некое озарение и понимание того, что до этого всё делал не так, тому же Девиду Нолену оно тоже пришло и его пропёрло написать Om.Next по мотивам GraphQL и Falcor, и мне пришло, т.к. задача этого требовала и были силы и время так решить задачу. Сейчас GraphQL не так уж плох и картина становится всё краше и краше, реализации становятся всё более матёрыми. То, что они намешали всё в одну кучу, так где-то это даже плюс, как в случае публичного апи – не надо придумывать что-то своё, берёшь любую библиотеку для клиента на любом языке и работаешь.

Edited at 2016-11-17 15:08 (UTC)

(Анонимно)
Отлично все расписал. Графкуэль крутая штука! Нужно просто время чтобы ее нормально раскурить.

без темы (Анонимно) Развернуть
Part III

Забыл дополнить, насколько удобнее GraphQL всяких сваггеров и прочих способов документировать рестовое апи. В GraphQL и подобных им документация генерируется автоматически, а чтобы всё было ещё красивее, в коде можно добавить более подробное описание полей и сущностей.

Ещё один важный момент – это типизация, имея чёткую хоть и банальную систему типов, есть возможность делать кодогенерацию для клиентов на Java, Swift и даже Flow: https://github.com/apollostack/apollo-ios, https://github.com/apollostack/apollo-codegen. Такое конечно давно есть для всяких IDL типа ProtoBuf, Thrift и прочих, но они имеют те же недостатки что и рест апи, а тут кодогенерация индивидуальная под каждый конкретный графовый запрос. Не надо вручную парсить json и компилятор проверит что результат правильно используется дальше по коду.

(Удалённый комментарий)
Я чувствую, что одна из проблем, которую дизайнеры часто не в состоянии осознать - это иерархия языков. И, соответственно, выбор, когда использовать регулярный, когда контекстно-свободный. А когда и вообще естественный.

Ага, в ASN.1 не заморачивались — сразу контекстно-свободный сделали, уж хоть то — хлеб.

(Удалённый комментарий)
Такое себе удовольствие - программировать ВСЮ бизнес логику внутри базы (а если не всю, то это еще хуже, ибо она будет размазана между бэкендом и базой).

(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
В разговоре с коллегой попробовал поподставлять RDF и "мерзкие капиталисты" вместо других имён, и возникло лютое желание порезать статью на шаблоны.

В смысле для копипасты шаблоны, чтобы можно было быстренько отвечать на очередные радостные возгласы по поводу новых технологий от <подставить>.


Статья начинается
Граф Кью Эль
"Интересная штука..."
Выясняется, что нет.


"....что бы не сказал Фейсбук, все слушают, раскрыв рот. Так Фейсбук закрепился законодателем мод по фронтенд-фреймворкам"
Ну и что? Это действительно так?


О чем пост?
О том, что вы талантливые разработчики, у которых до сих пор нет инструментов разработки?


Вы не знаете, как получить данные с сервера?


  • 1
?

Log in