Вы всерьез верите, что partial update — хорошее средство защиты от перезаписи при одновременном редактировании несколькими пользователями? :) Если Вася и Игорь одновременно загрузили страничку с формой обновления сущности, Вася поменял описание и цену, а Игорь поменял название и исправил опечатку в описании, то partial update никак не защитит от того, что Игорь перезапишет все изменения Васи в поле описания сущности. В таких случаях применяется что-то более нормальное — например, optimistic lock.
Ок, будет интересно почитать) Только хотел бы попросить кое-что, если не трудно — напишите, пожалуйста, в будущей статье, в чем основной профит от предлагаемого подхода. Потому что я на 90% уверен, что в GraphQL partial update реализуется только усложнением входных типов. А делать partial update ради partial update, либо бороться против 2Кб дополнительного трафика (или использовать это как основное средство против race conditions) выглядит не очень хорошей мотивацией)
Посмотрите первый вариант в моем комментарии выше. Я специально написал его для любителей выполнять одним методом все на свете. Второй вариант с двумя мутациями — это для приложений с четкими различающимися кейсами изменения модели. Например, отдельная форма изменения email, отдельная форма обновления имени и фамилии и т.п. Очевидно, что там даже на бэкенде логика разная будет выполняться в зависимости от формы, и делать это все одним методом с кучей if'ов, мягко говоря, не айс.
Также непонятно, если у вас CRUD, и на каждую сущность форма со всеми полями, зачем отправлять только часть из них, если у вас на руках полная модель.
Можно какие-то более конкретные примеры? Возможно, я просто не до конца понимаю, в чем такая огромная сложность в цепочке «взять объект, полученный из api» → «заменить поля, которые пользователь отредактировал» → «вызвать мутацию».
Может, это и делается немного проще с точки зрения отправки на сервер из фронтенда, но путем создания монструозных типов на сервере, где какой-нибудь Boolean может иметь не 2 значения (true/false), а 3 (true/false/undefined), что на мой взгляд еще хуже.
Предлагаю вместо абстрактных рассуждений рассмотреть конкретный пример.
Скажем, есть такой тип:
type User {
login: String!
role: String!
name: String
email: String
age: Int
}
Предположим, что в нашем приложении есть две формы: 1. Форма обновления «credentials» 2. Форма обновления «профиля». В первой форме нужно обновлять только поля «login», «role», а во второй поля «name», «email», «age».
Есть два варианта решения этой задачи:
Вариант 1, не очень удачный на мой взгляд — делаем input тип со всеми полями и одну мутацию:
input UserInput {
login: String!
role: String!
name: String
email: String
age: Int
}
type Mutation {
updateUser(input: UserInput!): User
}
Перед отображением форм достаем юзера с сервера через api. В первой форме поля «login» и «role» подставляем в UserInput из формы, остальные поля из того, что пришло из api. Во второй форме поля «name», «email», «age» подставляем в UserInput из формы, остальные поля из того, что пришло из api. Вызываем updateUser с заполненным UserInput.
Вариант 2, более адекватный — делаем свой input тип для каждого кейса и две мутации:
input UserCredentialsInput {
login: String!
role: String!
}
input UserProfileInput {
name: String
email: String
age: Int
}
type Mutation {
updateUserCredentials(input: UserCredentialsInput!): User
updateUserProfile(input: UserProfileInput!): User
}
В каждой форме используем соответствующий input и мутацию.
Именно так. Только не «либо ставите» null, а «либо устанавливается дефолтное значение».
Да, естественно, но это не меняет сути. Я думаю, вас также не устроило бы, если бы все атрибуты, которые вы не передали, сбрасывались бы на дефолтные значения.
Но тогда косяк в том, что концепция partial input просто перестает работать.
Другими словами, я не считаю понятия undefined и null тождественными.
Это не косяк, это ваша привычка мыслить подходами REST. Рассматривайте мутации GraphQL как просто функции в любом языке программирования, а input-типы как объекты в ООП (хорошо, без возможности иметь дефолтные значения атрибутов), и все станет восприниматься гораздо понятнее.
А вот при вводе, nullable — это вообще отдельная история. Это косяк уровня checkbox в HTML
Во-первых, перестаньте мыслить понятиями REST, когда работаете с GraphQL. Это другой подход, и мутации в GraphQL это не PATCH-методы из REST, а, скорее, аналог обычных функций в языках программирования. Когда, например, вы в любой ORM в метод «save» передаете объект как аргумент, вы же не можете каким-то образом «не передать» часть атрибутов этого объекта — вы либо передаете значения полей, которые изначально получили из БД, либо ставите null, и в БД тоже значение после сохранения становится null.
Во-вторых, если у вас есть кейсы, где для одной и той же модели нужно обновлять разные группы полей, никто не мешает создать для этого разные мутации. Маловероятно, что у вас 50 различных комбинаций обновляемых полей — чаще всего это 2-3 кейса на модель. Даже если смотреть с точки зрения обычных языков программирования — лучше создать несколько методов, каждый под свои нужды, чем один супер-метод, который делает все на свете.
4. Дженерики
А что не так в GraphQL c дженериками? А всё просто — их нет.
Зачем это нужно? Никто не пишет схему руками — для большинства языков программирования есть DSL для GraphQL с дженериками на уровне этого языка и всеми сопутствующими плюшками.
Именно по этой причине не очень хочется торопиться и становиться тимлидом раньше лет 30. Потому что тимлид это не программист, а менеджер с техническим бэкграундом. И этот бэкграунд просто не успевает восполняться до равного с другими разработчиками состояния со временем.
Я, конечно, попробую еще раз, но я вроде писал выше, что я пробовал запускать сборщик мусора после выполнения запросов и место не очищалось (REGISTRY_STORAGE_DELETE_ENABLED, само собой, true).
А вы сами хоть пробовали удалять образы через это api?) Какие бы запросы на удаление я не посылал — удаляется только метаинформация, но физически занятое место не освобождается. Пробовал чистить сборщиком мусора после выполнения запросов — тоже 0 эффекта.
P. S. Ну очевидно же, что не хочется хранить кучу образов старых версий) Если сборки идут каждый день + приложение не одно, а их несколько + образы весят под 2 Гб — посчитайте, насколько быстро забьется даже терабайтный хард.
Да ладно уж, описываемые вами проблемы не настолько суровы, чтобы так драматизировать)) То, что у вас вообще есть какая-то система учета задач, какой-то CI-сервер, да еще и внутренний менеджер репозиториев — уже оставляет позади X процентов IT-контор СНГ)
Я знаю людей, которые у себя в компании не используют ничего подобного, и код по FTP прямо на сервере правят) Да-да, в 2017 году)
Но, почему-то это «понимание бэка» часто сводится к «запили еще один костыль на бэке, иначе мне на фронте придется целых 3 лишних строчки кода написать».
Как это связано с вашим правом их наказывать? Еще ваша судьба от в компании от вашего начальника зависит, его тоже наказывать будете? То что вы от чего-то там зависите — это ваши личные проблемы. Это не дает вам никаких прав.
Безусловно, можно вот так вот философствовать про права и обязанности и про сущность бытия. А можно просто взять и построить хорошую и справедливую систему кнута и пряника, имея те полномочия, которые имеет управленец по отношению к команде. Я еще раз повторю, что под наказанием я не имею в виду наказания уровня средневековой инквизиции. Что я имею в виду, я писал выше.
А зачем человека выводить из зоны комфорта? Вы определитесь уже чего вам надо — сделать человеку неприятно или чтобы человек стал лучше и больше не косячил.
Да потому что такова природа человека. Пока он находится в зоне комфорта и нет никаких рисков выхода из нее, мало что поменяется. Сама история развития человечества это подтверждает.
Мне, честно говоря, поднадоела эта дискуссия. Я просто высказал, о чем бы мне было интересно прочитать в статье и чего здесь не хватает по моему мнению. Не стоит меня убеждать, что есть только пряник, а кнут не имеет смысла (в таком случае и вся эта статья не имеет смысла). Я работал в компаниях, где было довольно приемлемо организовано и то, и другое. Главное тут, чтобы каждый сотрудник заранее знал, за какие косяки и что именно может быть. А не так, чтобы это сваливалось как снег на голову.
Метод наказания работает только в случае если наказующий имеет значительную власть над наказуемым.
Я не знаю, какие вы имеете в виду наказания, для которых нужно тотальное превосходство и власть, но я имею в виду некие меры, которые будут мотивировать сотрудника не повторять своих косяков. Я уверен, что если вы являетесь пусть даже менеджером над программистами, то у вас уже в руках есть все необходимое. В ваших силах строить культуру в команде, разрабатывать хорошие правила, развивать понятную всем сотрудникам систему мотивации.
Задумайтесь, почему вы решили, что имеете право наказывать взрослого, постороннего вам человека? И что вас на самом деле интересует — наказть сотрудника или как-то его изменить?
Если вы являетесь менеджером над командой программистов, то они вам совсем не посторонние люди — от них зависит в том числе и ваша будущая судьба в компании. Что бы мне было интересно прочитать в данной статье, так это примеры наказаний (ну, или дисциплинарных мер и воздействий — называть можно как угодно), которые, как я писал выше, мотивируют сотрудника быть лучше, стараться как можно меньше повторять свои косяки. Не банальнейших угроз увольнением или выговоров на ковре, а мер, применение которых начинается в правильного выстраивания культуры в компании, мер, которые могут выводить человека из зоны комфорта, но при этом вызывать мысли не сбежать в другую компанию, а стать лучше и больше не косячить. Вот, про что, действительно, было бы интересно почитать.
В качестве примера: если в футбольном матче вы получите предупреждение за фол, вы ведь будете стараться играть аккуратнее в будущем, а не посчитаете это демотиватором и причиной вообще уйти из игры.
Вот представьте, что он не ваш сотрудник, а, например, сосед. Вы бы стали наказывать соседа за его характер/привычки?
Думаю, что каждый здравомыслящий человек что-то предпринял, если бы сосед своими действиями напрямую стал ухудшать качество его жизни.
В целом, понятно, что вы и понятия не имеете, как грамотно дисциплинарно воздействовать на сотрудника, чтобы это было для него не обидой, а стимулом исправиться. У вас почему-то только два варианта — либо человек идеален и не косячит (или косячит по незначительным мелочам), либо человек сразу списывается в утиль и ему как кирпич на голову сваливается угроза об увольнении. Но ведь есть еще куча промежуточных вариантов. Обратимся к реальной жизни — если человек украл пачку сигарет, это не значит, что его нужно сразу сажать в тюрьму на 10 лет, но и не значит, что нужно говорить «бери на здоровье» и отпускать просто так.
Да, есть хорошие программисты, но с отвратительным характером\привычками, которые иногда надо немного корректировать дисциплинарно (но это не значит, что их нужно увольнять). А сидеть и пускать все на самотек не представляется достойным вариантом для человека, который считает себя хорошим руководителем.
Более бесполезного способа, чем грозить увольнением сложно даже придумать в применении к хорошим программистам.
Я еще ни разу не видел, чтобы такое работало, даже если у программиста ЗП в данной компании на 20-30% выше рынка.
Мой вопрос был именно про то, как наказывать за разные косяки. Отдача ниже 100% это не косяк и вообще другая тема.
Увольнение это крайняя мера, и очень глупо грозить им при каждом случае. Точно так же, как с пистолетом — лучше не вытаскивать, если не решился стрелять.
partial update
— хорошее средство защиты от перезаписи при одновременном редактировании несколькими пользователями? :) Если Вася и Игорь одновременно загрузили страничку с формой обновления сущности, Вася поменял описание и цену, а Игорь поменял название и исправил опечатку в описании, тоpartial update
никак не защитит от того, что Игорь перезапишет все изменения Васи в поле описания сущности. В таких случаях применяется что-то более нормальное — например, optimistic lock.partial update
реализуется только усложнением входных типов. А делатьpartial update
радиpartial update
, либо бороться против 2Кб дополнительного трафика (или использовать это как основное средство против race conditions) выглядит не очень хорошей мотивацией)Посмотрите первый вариант в моем комментарии выше. Я специально написал его для любителей выполнять одним методом все на свете. Второй вариант с двумя мутациями — это для приложений с четкими различающимися кейсами изменения модели. Например, отдельная форма изменения email, отдельная форма обновления имени и фамилии и т.п. Очевидно, что там даже на бэкенде логика разная будет выполняться в зависимости от формы, и делать это все одним методом с кучей if'ов, мягко говоря, не айс.
Также непонятно, если у вас CRUD, и на каждую сущность форма со всеми полями, зачем отправлять только часть из них, если у вас на руках полная модель.
Может, это и делается немного проще с точки зрения отправки на сервер из фронтенда, но путем создания монструозных типов на сервере, где какой-нибудь
Boolean
может иметь не 2 значения (true/false
), а 3 (true/false/undefined
), что на мой взгляд еще хуже.Скажем, есть такой тип:
Предположим, что в нашем приложении есть две формы: 1. Форма обновления «credentials» 2. Форма обновления «профиля». В первой форме нужно обновлять только поля «login», «role», а во второй поля «name», «email», «age».
Есть два варианта решения этой задачи:
Вариант 1, не очень удачный на мой взгляд — делаем input тип со всеми полями и одну мутацию:
Перед отображением форм достаем юзера с сервера через api. В первой форме поля «login» и «role» подставляем в
UserInput
из формы, остальные поля из того, что пришло из api. Во второй форме поля «name», «email», «age» подставляем вUserInput
из формы, остальные поля из того, что пришло из api. ВызываемupdateUser
с заполненнымUserInput
.Вариант 2, более адекватный — делаем свой input тип для каждого кейса и две мутации:
В каждой форме используем соответствующий input и мутацию.
Да, естественно, но это не меняет сути. Я думаю, вас также не устроило бы, если бы все атрибуты, которые вы не передали, сбрасывались бы на дефолтные значения.
Это не косяк, это ваша привычка мыслить подходами REST. Рассматривайте мутации GraphQL как просто функции в любом языке программирования, а input-типы как объекты в ООП (хорошо, без возможности иметь дефолтные значения атрибутов), и все станет восприниматься гораздо понятнее.
Во-первых, перестаньте мыслить понятиями REST, когда работаете с GraphQL. Это другой подход, и мутации в GraphQL это не PATCH-методы из REST, а, скорее, аналог обычных функций в языках программирования. Когда, например, вы в любой ORM в метод «save» передаете объект как аргумент, вы же не можете каким-то образом «не передать» часть атрибутов этого объекта — вы либо передаете значения полей, которые изначально получили из БД, либо ставите null, и в БД тоже значение после сохранения становится null.
Во-вторых, если у вас есть кейсы, где для одной и той же модели нужно обновлять разные группы полей, никто не мешает создать для этого разные мутации. Маловероятно, что у вас 50 различных комбинаций обновляемых полей — чаще всего это 2-3 кейса на модель. Даже если смотреть с точки зрения обычных языков программирования — лучше создать несколько методов, каждый под свои нужды, чем один супер-метод, который делает все на свете.
Зачем это нужно? Никто не пишет схему руками — для большинства языков программирования есть DSL для GraphQL с дженериками на уровне этого языка и всеми сопутствующими плюшками.
P. S. Ну очевидно же, что не хочется хранить кучу образов старых версий) Если сборки идут каждый день + приложение не одно, а их несколько + образы весят под 2 Гб — посчитайте, насколько быстро забьется даже терабайтный хард.
Я знаю людей, которые у себя в компании не используют ничего подобного, и код по FTP прямо на сервере правят) Да-да, в 2017 году)
Безусловно, можно вот так вот философствовать про права и обязанности и про сущность бытия. А можно просто взять и построить хорошую и справедливую систему кнута и пряника, имея те полномочия, которые имеет управленец по отношению к команде. Я еще раз повторю, что под наказанием я не имею в виду наказания уровня средневековой инквизиции. Что я имею в виду, я писал выше.
Да потому что такова природа человека. Пока он находится в зоне комфорта и нет никаких рисков выхода из нее, мало что поменяется. Сама история развития человечества это подтверждает.
Мне, честно говоря, поднадоела эта дискуссия. Я просто высказал, о чем бы мне было интересно прочитать в статье и чего здесь не хватает по моему мнению. Не стоит меня убеждать, что есть только пряник, а кнут не имеет смысла (в таком случае и вся эта статья не имеет смысла). Я работал в компаниях, где было довольно приемлемо организовано и то, и другое. Главное тут, чтобы каждый сотрудник заранее знал, за какие косяки и что именно может быть. А не так, чтобы это сваливалось как снег на голову.
Я не знаю, какие вы имеете в виду наказания, для которых нужно тотальное превосходство и власть, но я имею в виду некие меры, которые будут мотивировать сотрудника не повторять своих косяков. Я уверен, что если вы являетесь пусть даже менеджером над программистами, то у вас уже в руках есть все необходимое. В ваших силах строить культуру в команде, разрабатывать хорошие правила, развивать понятную всем сотрудникам систему мотивации.
Если вы являетесь менеджером над командой программистов, то они вам совсем не посторонние люди — от них зависит в том числе и ваша будущая судьба в компании. Что бы мне было интересно прочитать в данной статье, так это примеры наказаний (ну, или дисциплинарных мер и воздействий — называть можно как угодно), которые, как я писал выше, мотивируют сотрудника быть лучше, стараться как можно меньше повторять свои косяки. Не банальнейших угроз увольнением или выговоров на ковре, а мер, применение которых начинается в правильного выстраивания культуры в компании, мер, которые могут выводить человека из зоны комфорта, но при этом вызывать мысли не сбежать в другую компанию, а стать лучше и больше не косячить. Вот, про что, действительно, было бы интересно почитать.
В качестве примера: если в футбольном матче вы получите предупреждение за фол, вы ведь будете стараться играть аккуратнее в будущем, а не посчитаете это демотиватором и причиной вообще уйти из игры.
Думаю, что каждый здравомыслящий человек что-то предпринял, если бы сосед своими действиями напрямую стал ухудшать качество его жизни.
Да, есть хорошие программисты, но с отвратительным характером\привычками, которые иногда надо немного корректировать дисциплинарно (но это не значит, что их нужно увольнять). А сидеть и пускать все на самотек не представляется достойным вариантом для человека, который считает себя хорошим руководителем.
Я еще ни разу не видел, чтобы такое работало, даже если у программиста ЗП в данной компании на 20-30% выше рынка.
Мой вопрос был именно про то, как наказывать за разные косяки. Отдача ниже 100% это не косяк и вообще другая тема.
Увольнение это крайняя мера, и очень глупо грозить им при каждом случае. Точно так же, как с пистолетом — лучше не вытаскивать, если не решился стрелять.