Т.е., чтобы пользоваться такой системой постановки паролей на моих любимых сайтах, мне надо каждый раз вводить мастер-пароль? Если так, то через два-три сайта я такую заботу отключу нафиг.
Если увеличить длинну второго пароля хотябы до половины длины первого, они будут относительно равны по энтропийности.
В современных подходах энтропийность стоит далеко не на первом месте. Основную роль играют векторы атаки и их вероятность. Компрометация незапоминаемого пароля на порядки выше, чем у равно по энтропийности, но легко запоминаемого.
Сейчас три ключевых характеристики к парольной защиты следующие:
1. Отсутствие необходимости периодической смены пароля. Пароль должен меняться только при превышении вероятностью, что он был скомпрометирован, определенного порога.
2. Отсутствие искусственной сложности, не позволяющей создавать равные по энтропии, но легко запоминающиеся пароли.
3. Проверка наличия в паролях часто используемых и скомпрометированных паролей.
Добавьте ещё головную боль в виде размазанной бизнес-логики по мутациям / орм с кучей дублируемого кода, для чего пришлось использовать написать генераторы кода.
Как итог можно смело прогнозировать, что через определенное время проект будет быстрее и дешевле переписать, чем развивать. Так что не используйте graphql
Сколько ни читаю посты об GraphQL, не могу понять чем он принципиально лучше существующих уже давным давно URI-совместимых query language-ей. Например, RQL или odata. Они прекрасно решают проблему выбора необходимых полей, поддерживают фильтрацию, паджинацию и все остальное. В отличии от GraphQL они не противопоставляют себя REST-у, а отлично его дополняют.
Киллер-фича графа — отсутствие необходимости версионировать апи. Из чего вытекает простота использования и поддержки точки взаимодействия клиента и приложения.
Граф противопоставляется ресту, потому что идеологически граф не общается с хранилищем, а только с репозиториями. Рест-апи в своем развитии обзаводится особыми эндпоинтами, которые получают сложные наборы данных и обзаводятся слоем логики, позволяющем получить эти данные из хранилищ наиболее оптимальным способом. И очень часто при внедрении графа возникает именно вопрос о том, как это повторить для графа. Никак. Граф не должен знать ничего о том, как хранятся данные. Он должен знать только то, какой севрис обслуживает какие типы данных.
Добавлю, что вы можете создать два типа данных (запроса), например, UserPublic и UserPrivate, что будет аналогом двух ендпоинтов
Это нарушает саму идеологию графа. Запросить пользователя мы можем в любом месте любого запроса, который имеет связь с пользователем: { article { user { id } } }
Если мы будем использовать разные названия типов в зависимости от прав, то убъем универсальность доступа к данным.
Это делается на уровне генерации типа данных для схемы. Если в схеме нет какого-то типа или поля в типе, то их запрос приведет к общей ошибке обработки запроса (запрос несуществующего типа или несуществующего поля).
В общем случае это решается наличием соответствующего функционала у репозитория. Тип возвращаемых данных — это один из его интерфейсов. Используя этот тип данных репозиторий преобразует внутреннее хранение полученных из хранилища данных в стукруту, которая передается пользователю. Аналогичным образом граф у репозитория получает этот тип данных в соответствующем формате.
Ограничение доступа остаётся на уровне репозитория, который сам фильтрует, по своей внутренней логике, какие поля кому доступны. Что клиент не может получить у этого репозитория недоступные ему поля (потому что всякая выдача проходит через преобразование в этот тип данных), что граф, запрашивая схему для типа данных, получает только тот набор полей, который доступен данному пользователю.
Когда используется схема «клиент -> запрашивает данные через граф -> который, опираясь на описание типов, запрашивает нужные данные в нужных репозиториях -> которые, основываясь своей бизнес-логике, запрашивают данные из своих хранилищ», то вопросов, для чего нужен граф и какие задачи он решает, не возникает.
Почти всем нерешаемые проблемы графа связаны с тем, что его пытаются применить не по назначению. Возьмем, например, пагинацию.
Есть ОРМ, которая поддерживает работу с графом. Прикручиваем пагинатор к ОРМ и через этот пагинатор ходим напрямую в ОРМ. И имеем все те проблемы, которые описывают в каждой второй статье применения графа.
Как это решается через вышеописанную схему?
Создается тип пагинированных данных. Интерфейс репозиториев расширяется, чтобы они умели отдавать данные согласно новому типу данных. Как результат пагинатором ОРМ пользуются репозитории. А граф запрашивает у репозиториев данные соответствующего типа. Задача получения данных и оптимизации запросов остается на уровне модели, которую использует репозиторий для работы с хранилищем.
Вместо этого делают фиксированный набор полей, на выборку которого затачивают запрос и т.д.
Эти технологии применяются на разных слоях приложения.
Если в модели есть сложно вычисляемое поле, то на уровне агрегации данных модели решается задача, как это поле получать быстро.
Перед графом же ставится задача отдать любое запрошенное поле модели.
В конце концов такие модели с тяжелой логикой получения данных обзаводятся слоем кеша со сквозной записью.
Если самим графом за данными не ходить, четко разделяя уровни ответственности, то этой проблемы просто нет как таковой.
Ведь в зависимости от того, какие поля нужны, приходится сильно варьировать запрос, чтобы не убить производительность.
Архитектурно неправильно графом ходить в хранилище данных. Граф является интерфейсом (точнее поля типа данных, для которого строится схема графа) к репозиторию. Каждый тип данных (пользователь, статья и т.п.) — это репозитории, к которым обращается граф. Как эти репозитории получают данные, как они их агрегируют, кешируют — это их детали реализации.
Рассмотрите абсолютно любую бизнес-модель с позиции, что у вас есть универсальный апи-метод, позволяющий получить каждое из полей этой модели. Как это поле будет собираться — это дело самой бизнес-модели. Можно анализировать граф-запрос, но сама логика графа подразумевает, что запрашиваться будет самый разный набор полей, поэтому чаще всего эффективнее кешировать либо всю модель, либо поля модели.
При использовании графа ответственность смещается с SLA на конкретный эндпоинт (с соответствующими уровнями оптимизации запросов) на SLA доступа ко всем предоставляемым данным. Решается задача не оптимизации медленных запросов к данным, а как отдавать данные вне зависимости от того, какие там могут быть запросы.
Я правильно, что на практике сервер всё равно поддерживает предопределённые запросы и наборы полей под конкретные кейсы? Если да, то в чём тут преимущество?
Я выделил бы два ключевых преимущетва.
У нас есть универсальный геттер для данных. На уровне описания типов бизнес-моделей описываются их поля и связи (поля с типами других моделей). На основе этих типов потом строится вся схема графа. Бонусом можно на основе внутренней логики регулировать, какие типы кто будет видеть. Если в описании схемы какого-то запрошенного поля нет (вырезано из-за отсутствия прав), то запрос с таким полем не пройдет сам по себе. Логика резолва всех указанных в графе полей спускается на уровень ниже, для которого декларируемые поля являются интерфейсом, согласно которому сервис должен уметь возвращать данные
Второе преимущество в сеттерах (мутации). С одной стороны для каждой операции бизнес-логики пишется своя мутация (как бы аналог эндпоинта в рест), но из-за вышеописанного преимущества с декларативным способом описания, методы бизнес-логики превращаются в мутации, где наборы полей описываются таким же декларативным методом. А сама бизнес-логика уходит на следующий уровень, для которого мутация становится просто интерфейсом.
В итоге поддержка апи сводится к декларации получаемых данных и декларации методов изменения данных. Сама реализация же может делаться где угодно и как угодно, пока она использует описанные в графе декларации в качестве интерфейса.
Т.е., чтобы пользоваться такой системой постановки паролей на моих любимых сайтах, мне надо каждый раз вводить мастер-пароль? Если так, то через два-три сайта я такую заботу отключу нафиг.
В современных подходах энтропийность стоит далеко не на первом месте. Основную роль играют векторы атаки и их вероятность. Компрометация незапоминаемого пароля на порядки выше, чем у равно по энтропийности, но легко запоминаемого.
Сейчас три ключевых характеристики к парольной защиты следующие:
1. Отсутствие необходимости периодической смены пароля. Пароль должен меняться только при превышении вероятностью, что он был скомпрометирован, определенного порога.
2. Отсутствие искусственной сложности, не позволяющей создавать равные по энтропии, но легко запоминающиеся пароли.
3. Проверка наличия в паролях часто используемых и скомпрометированных паролей.
А зачем на клиенте схему описывать?
Добавьте ещё головную боль в виде размазанной бизнес-логики по мутациям / орм с кучей дублируемого кода, для чего пришлось использовать написать генераторы кода.
Как итог можно смело прогнозировать, что через определенное время проект будет быстрее и дешевле переписать, чем развивать. Так что не используйте graphql
Киллер-фича графа — отсутствие необходимости версионировать апи. Из чего вытекает простота использования и поддержки точки взаимодействия клиента и приложения.
Граф противопоставляется ресту, потому что идеологически граф не общается с хранилищем, а только с репозиториями. Рест-апи в своем развитии обзаводится особыми эндпоинтами, которые получают сложные наборы данных и обзаводятся слоем логики, позволяющем получить эти данные из хранилищ наиболее оптимальным способом. И очень часто при внедрении графа возникает именно вопрос о том, как это повторить для графа. Никак. Граф не должен знать ничего о том, как хранятся данные. Он должен знать только то, какой севрис обслуживает какие типы данных.
Это нарушает саму идеологию графа. Запросить пользователя мы можем в любом месте любого запроса, который имеет связь с пользователем: { article { user { id } } }
Если мы будем использовать разные названия типов в зависимости от прав, то убъем универсальность доступа к данным.
В общем случае это решается наличием соответствующего функционала у репозитория. Тип возвращаемых данных — это один из его интерфейсов. Используя этот тип данных репозиторий преобразует внутреннее хранение полученных из хранилища данных в стукруту, которая передается пользователю. Аналогичным образом граф у репозитория получает этот тип данных в соответствующем формате.
Ограничение доступа остаётся на уровне репозитория, который сам фильтрует, по своей внутренней логике, какие поля кому доступны. Что клиент не может получить у этого репозитория недоступные ему поля (потому что всякая выдача проходит через преобразование в этот тип данных), что граф, запрашивая схему для типа данных, получает только тот набор полей, который доступен данному пользователю.
Почти всем нерешаемые проблемы графа связаны с тем, что его пытаются применить не по назначению. Возьмем, например, пагинацию.
Есть ОРМ, которая поддерживает работу с графом. Прикручиваем пагинатор к ОРМ и через этот пагинатор ходим напрямую в ОРМ. И имеем все те проблемы, которые описывают в каждой второй статье применения графа.
Как это решается через вышеописанную схему?
Создается тип пагинированных данных. Интерфейс репозиториев расширяется, чтобы они умели отдавать данные согласно новому типу данных. Как результат пагинатором ОРМ пользуются репозитории. А граф запрашивает у репозиториев данные соответствующего типа. Задача получения данных и оптимизации запросов остается на уровне модели, которую использует репозиторий для работы с хранилищем.
Эти технологии применяются на разных слоях приложения.
Если в модели есть сложно вычисляемое поле, то на уровне агрегации данных модели решается задача, как это поле получать быстро.
Перед графом же ставится задача отдать любое запрошенное поле модели.
В конце концов такие модели с тяжелой логикой получения данных обзаводятся слоем кеша со сквозной записью.
Если самим графом за данными не ходить, четко разделяя уровни ответственности, то этой проблемы просто нет как таковой.
Архитектурно неправильно графом ходить в хранилище данных. Граф является интерфейсом (точнее поля типа данных, для которого строится схема графа) к репозиторию. Каждый тип данных (пользователь, статья и т.п.) — это репозитории, к которым обращается граф. Как эти репозитории получают данные, как они их агрегируют, кешируют — это их детали реализации.
Рассмотрите абсолютно любую бизнес-модель с позиции, что у вас есть универсальный апи-метод, позволяющий получить каждое из полей этой модели. Как это поле будет собираться — это дело самой бизнес-модели. Можно анализировать граф-запрос, но сама логика графа подразумевает, что запрашиваться будет самый разный набор полей, поэтому чаще всего эффективнее кешировать либо всю модель, либо поля модели.
При использовании графа ответственность смещается с SLA на конкретный эндпоинт (с соответствующими уровнями оптимизации запросов) на SLA доступа ко всем предоставляемым данным. Решается задача не оптимизации медленных запросов к данным, а как отдавать данные вне зависимости от того, какие там могут быть запросы.
Я выделил бы два ключевых преимущетва.
У нас есть универсальный геттер для данных. На уровне описания типов бизнес-моделей описываются их поля и связи (поля с типами других моделей). На основе этих типов потом строится вся схема графа. Бонусом можно на основе внутренней логики регулировать, какие типы кто будет видеть. Если в описании схемы какого-то запрошенного поля нет (вырезано из-за отсутствия прав), то запрос с таким полем не пройдет сам по себе. Логика резолва всех указанных в графе полей спускается на уровень ниже, для которого декларируемые поля являются интерфейсом, согласно которому сервис должен уметь возвращать данные
Второе преимущество в сеттерах (мутации). С одной стороны для каждой операции бизнес-логики пишется своя мутация (как бы аналог эндпоинта в рест), но из-за вышеописанного преимущества с декларативным способом описания, методы бизнес-логики превращаются в мутации, где наборы полей описываются таким же декларативным методом. А сама бизнес-логика уходит на следующий уровень, для которого мутация становится просто интерфейсом.
В итоге поддержка апи сводится к декларации получаемых данных и декларации методов изменения данных. Сама реализация же может делаться где угодно и как угодно, пока она использует описанные в графе декларации в качестве интерфейса.