Как стать автором
Обновить
2
0.1

Пользователь

Отправить сообщение
сервер доставит ответы максимально быстро, без лага между ними

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


REST совершенно не мешает вам возвратить в одном ресурсе хоть всю БД

Но в одном случае клиент хочет 3 связанных сущности, в другом — пять, в третьем вооще ни одной.
Варианты решения:


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

Хороший аргумент.


Тут два аспекта:


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

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

Loopback — интересно, спасибо. Вы, конечно, правы, что можно и в REST сделать. В конце концов, в GraphQL никакого волшебства же нет.


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


С REST клиент вынужден дождаться результатов первого запроса (список проектов), чтобы потом, получив их id, запросить список пользователей на этих проектах.
С HTTP2 можно было бы использовать Server Push в этом сценарии. Но для этого сервер должен как-то знать, что клиенту потребуются связанные сущности. Тогда мы все равно придем к чему-то вроде GraphQL.

А вам просто потроллить или разобраться?


Я вот, допустим, нигде не говорил, что из базы надо выгребать все атрибуты. В резолвер передается список атрибутов, запрошенных клиентом. Если это важно для производительности, никто не мешает грузить из базы только то, что надо.
В hello-world туториалах это может быть не упомянуто, но это не значит, что так нельзя.


Отсылку к js я вообще не понял. Какое отношение клиентский js имеет к тому, как бэкенд работает с базой, чтобы удовлетворить запрос клиента?

В плане документации и части инструментов для разработки, наверное, будет похоже.


Но не забываем, что GraphQL и другие задачи решает. В частности, позволяет клиенту указать, какое подмножество данных его интересует в данном запросе (вместо запроса всех атрибутов сущности), позволяет скомбинировать несколько запросов один.
Причем на бэкенде эту логику самостоятельно писать не надо: сам пишешь только запросы к сущностям в БД (логика приложения), а парсинг запросов, фильтрация атрибутов, форматирование результата реализуются библиотечным кодом.

Это проблема любых тестов, а не только "таких".
Если требования меняются, тесты тоже должны модифицироваться соответственно.

иногда полезно, когда баг виден невооружённым глазом

Во, интересная мысль!


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


Если бы баг был виден сразу невооруженным глазом, то, в принципе, и так было бы понятно как его воспроизвести, без тайм тревела.

Да нормальный вышел тест. Я потом из дампа выкинул несущественные детали.


А насчет "непонятно как пришли" — так это и не надо. Надо, чтоб переход от этого к состояния к новому правильно происходил.

Если все, что приложение делает, — это запрос и отображение данных с бэкенда, то dev tools вряд ли пригодится.
Когда добавляется более-менее сложная логика на клиент — тут уже помогает.


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


В какой-то момент в процессе тестирования у меня появляется дублирующееся ребро, которого быть не должно. К этому моменту я уже много покликал по графу, добавлял, удалял — воспроизвести проблему с нуля было бы проблематично.
А с открытым Redux Dev Tools я прокликал по истории состояний, нашел первый шаг, который привел к проблеме. Там же из Dev Tools скопировал текущее состояние (json), вставил практически как есть в юнит-тест и затем починил.

Как раз GraphQL предоставляет способ формального описания того, "как будет структурироваться в ресурсах прикладная задача" — GraphQL Schema. И формат этого описания — стандартный.


Свой RESTful сервис я тоже смогу как-то формально описать. Но язык этого описания будет какой-то кастомный. Поэтому инструменты для работы с ним мне придется писать самому.


HAL/HATEOAS — это другое. Они позволяют расширить "данные" неким стандартным способом (запросив сущность Пользователь я получаю, помимо имени и имейла, еще ссылки на связанные с этим пользователем сущности).
А GraphQL — это "метаданные". Он описывает, какие типы сущностей вообще есть и как связаны.

Принципиальное отличие: GraphQL — конкретная спецификация, в то время как REST это парадигма, которую каждый готовит по-своему.
Однозначность спецификации GraphQL позволяет писать и использовать универсальные инструменты: тот же apollo-client, стандартные реализации GraphQL-сервера на разных языках.

А где ссылка на оригинал?


У меня есть подозрение, что


вместо создания обратной последовательности вызова компилятор генерирует скачок

это не совсем то, что хотел сказать автор.


По существу:
Крокфорд, конечно, голова — но в данном докладе он кое-где гонит :)


  • Разве Алан Кей придумал C++, а не Smalltalk?
  • Pascal сюда зачем-то сюда приплел в контексте "начала объектно-ориентированного программирования". Почему не тот же Smaltalk? Да даже C++, если верить википедии, был создан раньше, чем Object Pascal (не путаем с оригинальным Pascal, в котором объектов не было
  • Консервативность в принятии новых языков разработчиками. Имхо вопрос больше в аппаратных возможностях. Высокие абстракции, как правило, требуют больше аппаратных ресурсов. Когда производительность стала позволять, разработчики стали переключаться на более высокоуровневые инструменты.

Ускорение работы с БД получается только при отправке нескольких запросов с одной структурой, но разными параметрами.


Если же запросы все разные, то работа с БД замедляется: вместо одного запроса к БД нужно сделать два (prepare + execute).

Так вот почему у меня мозг взрывается от этого кода. Все дело в недостающем case!


Если серьезно, то у меня вопрос:
Я вот знаком со Скалой преимущественно по статьям на Хабре :). И для меня конструкции типа определения Parser в статье — вынос мозга каждый раз.
А вы правда привыкли к ней настолько, чтобы легко и непринужденно оперировать подобными сущностями?
Или все еще требуется значительное усилие, чтобы разобраться, что к чему?


Написать-то один раз можно (даже я, наверное, справлюсь — с n-ной попытки). Но потом же кто-то этот код регулярно читает.


Меня действительно этот вопрос интересует.

Для этого существуют .d.ts файлы, которые описывают сигнатуры библиотечных классов/методов.


Допустим, вот описание для document.addEventListener.
Здесь утверждается, что сигнатура коллбэка будет EventListenerOrEventListenerObject, который в свою очередь ссылается на EventListener:


interface EventListener {
    (evt: Event): void;
}

Отсюда видно, что придет в аргументах функции: это объект типа Event

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


В примере же, приведенном в статье, класс Organization не реализует интерфейс Employee — таким образом, он не является композитом в том смысле, который закладывается в данном шаблоне.


Более правильный пример был бы что-то вроде:


interface Assignee {
  public function canHandleTask($task): bool;
  public function takeTask($task);
}

class Employee implements Assignee {
  // реализуем методы интерфейса
}

class Team implements Assignee {
  /** @var Assignee[] */
  private $assignees;

  // вспомогательные методы для управления композитом:
  public function add($assignee);
  public function remove($assignee);

  // метода интерфейса Employee

  public function canHandleTask($task): bool {
    foreach ($this->assignees as $assignee) if ($assignee->canHandleTask($task)) return true;
    return false;
  }
  public function takeTask($task) {
    // может быть разная имплементация - допустим, некоторые задания требуют нескольких человек из команды одновременно
    // в простейшем случае берем первого незанятого работника среди this->assignees
    $assignee = ...;
    $assignee->takeTask($task);
  }
}

// Использование:

class TaskManager {
  private $assignees;
  public function performTask($task) {
    foreach ($this->assignees as $assignee) {
       if ($assignee->canHandleTask($task)) {
         $assignee->takeTask($task);
         return;
       }
    }

    throw new Exception('Cannot handle the task - please hire more people');
  }
}

$employee1 = new Employee();
$employee2 = new Employee();
$employee3 = new Employee();
$employee4 = new Employee();
$team1 = new Team([$employee3, $employee4);

// ВНИМАНИЕ: передаем команду в taskManager как единый композит.
// Сам taskManager не знает, что это команда и работает с ней без модификации своей логики.
$taskManager = new TaskManager([$employee1, $employee2, $team1]);
$taskManager->preformTask($task);

@TC40 Немного оффтоповый вопрос:
А имеет ли эквайр право не обслуживать карты, выпущенные некоторыми эмитентами — в частности, по географическому признаку?
Допустим, интернет-эквайринг от альфа-банка принимает только платежи с карт, выпущенных в России. К примеру, я не мог зарубежную карту использовать в Яндекс.Такси или при оплате покупки в М-Видео (эквайринг от Альфа-банка).

А почему договариваться про интерчендж должен ритейл? Это же внутренние взаимоотношения между банками.


Разве не в интересах самого банка-эквайра договориться о менее высокой комиссии с тем или иным эмитентом? Тогда он сможет предлагать услуги эквайринга своим клиентам дешевле — конкурентное преимущество.


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

А, теперь ясно.
По сути, это вариации на тему недостаточного трафика (первый фактор). Если для какой-то группы юзеров что-то не работает, грубо говоря считаем, что от них трафика нет. То есть ААБ говорит нам о недостаточности выборки, когда мы априорно считали, что выборка уже должна быть значимой.

Информация

В рейтинге
3 532-й
Зарегистрирован
Активность