Системный сдвиг
9.42K subscribers
227 photos
7 videos
18 files
220 links
Авторский канал Юрия Куприянова. Обучаю системных аналитиков. Пишу про нетривиальные темы в анализе, проектировании систем, управлении и обучении.

Программный директор WAW, член ПК Flow, ЛАФ.

Контакты: @YuryKupriyanov

Курсы: https://systems.education
Download Telegram
Вообще я сегодня про другое хотел написать, но невозможно пройти мимо актуальной темы: буквально на наших глазах развернулась поучительная история: как Яндекс почти положил службу точного времени в Рунете.

Краткое содержание: с середины октября российские сервера точного времени (NTP) второго уровня, поддерживаемые сообществом (то есть, люди по собственной инициативе у себя их развернули на роутерах, на своих серверах), испытали практически DDoS-атаку — трафик на них катастрофически вырос, и люди стали их отключать. Из 140 серверов осталось 5. Оказалось, этот трафик посылают умные колонки от Яндекса, в которые с очередным обновлением прошивки приехал баг, заставляющий их слать запросы на синхронизацию времени каждые 5 секунд.

Обнаружил это один из участников пула NTP, и опубликовал 24 ноября статью на Хабре, чтобы привлечь внимание к проблеме. Сейчас Яндекс баг уже признал и исправил, и пообещал установить собственные сервера точного времени, а не полагаться на общественные.

Вопрос методический: чья эта область ответственности?

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

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

И когда это устройство было экспериментальным — никто особенно не задумывался над серьезностью такого взаимодействия. Ну, сели на общий pool.ntp.org, который используется всеми линуксами и большинством устройств. Оно работает, и ладно.

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

На мой взгляд, здесь есть три момента, которые относятся к задачам системного аналитика:

1. Анализ эффектов при масштабировании (рост нагрузки на смежные системы, превышение лимитов внешних API);
2. Анализ условий использования внешних систем (у проекта NTPPool есть гайдлайны для вендоров оборудования, им нужно следовать);
3. Контроль и учет всех входов и выходов системы (Сергей Нужненко рассказывал об этом упражнении на Flow).
А написать я хотел про синхронные и асинхронные взаимодействия, по следам предыдущего (теперь уже пред-предыдущего) поста.

Андрей Бураков справедливо заметил, что WebSockets-то асинхронный, а я его в синхронные записал, вот позор.

Но логика у меня в этот момент была вот какая: если нам нужен быстрый отклик — мы берем паттерн "запрос-ответ", то есть RPC и REST. Но если нам нужен ещё более быстрый отклик — мы берём WebSockets, где взаимодействие асинхронное. Ну или используем Long Polling, WebHooks или MQTT — все они асинхронные, и все применяются, когда нам нужно очень быстро отреагировать на событие.

Следующий шаг в этом же направлении, но на другом уровне, сделал Google со своим протоколом QUIC, заменяющим TCP. Потому что установка соединения TCP — слишком дорогая и долгая операция, а делать её приходится почти при каждом запросе (да, есть keep-alive, тогда соединения будут держаться дольше, но у этого есть и обратная сторона — именно это соединение нужно использовать, пока оно живо. Иначе у вас будет много живых соединений и, соответственно, много занятых портов).

Протокол QUIC в основном ориентирован на веб-браузеры, а веб-браузеры имеют обыкновение запрашивать много разных ресурсов одновременно. Хотя каждый запрос сам по себе синхронный, выполняются они в java script'е асинхронно, через промисы и async/await, и про это есть много шуток у фронтендеров — очень больная тема, сложно понять.

Хуже того, ваш компьютер внутри тоже весь работает асинхронно — через механизм прерываний. Любое действие — нажатие на кнопку на клавиатуре, движение мышью, поступление нового пакета на сетевой адаптер — на самом деле останавливает выполняемую программу и вызывает специальный обработчик. И очереди, очереди везде!

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

Получается, в этом в целом асинхронном мире есть довольно узкая прослойка — место для условно синхронных коммуникаций, где-то в районе от 100 миллисекунд до секунды, где они могут работать. Именно здесь работают все пользовательские интерфейсы, и именно в этом временном промежутке вырос весь Web на базе REST API.

По случайному совпадению, этот диапазон как раз соответствует человеческому восприятию "мгновенной реакции". Она как раз примерно от 100-120 мс у гонщиков F1, пилотов истребителей и топовых кибер-спортсменов, до 250-300 мс — у обычных людей. Можете проверить себя: https://humanbenchmark.com/tests/reactiontime , у меня как раз 253 получилось в среднем. Хорошее пятничное развлечение :)

Так случайно совпало, что типичные http-запросы выполняются как раз примерно за 300-900 мс (передача данных через websocket — 200 мс). Действий быстрее 13 мс человек вообще не воспринимает (скорость обмена в 5G-сетях — 15 мс, это быстро). Аукцион рекламодателей за рекламное место на веб-странице — RTB — занимает 100-200 мс. В высокочастотном трейдинге решение о сделке принимается за микросекунды. На таких скоростях важным становится расстояние между серверами, поэтому их ставят прямо в датацентре биржи или вообще втыкают прямо в PCI-шину биржевого сервера. Вызов обработчика прерываний вообще в тактах процессора считается — это наносекунды для современных компьютеров.

Такие скорости у нас. И в некоторых случаях становится принципиально, что действие происходит не мгновенно, а за конкретное не нулевое время.
На тренинге по интеграциям возник вопрос: что куда класть в http-запросе (в REST API). Решил разложить по полочкам (pun intended).

Полочек в http четыре штуки:

➡️ путьpath или route, эндпоинт, он же на жаргоне яндексоидов "ручка" (то, что после адреса сервера, за символом '/' — иерархия типов ресурсов и их идентификаторов. По аналогии с путем к файлу на диске, в пути говорят о вложенности — как будто каждый следующий уровень в цепочке '/' вложен в предыдущий. То есть, /orders/123456 — это заказ с id=123456, а /orders/123456/items — это перечень товаров в этом заказе, товары "вложены" в заказ)

➡️ параметры запроса, или query (то, что в конце URL, за символом '?' — перечисление параметров в формате имя=значение, разделенных &.)

Метод http, путь, параметры и версия протокола вместе называется называется строкой запроса или стартовой строкой. Строки запроса сохраняются в логах сервера.

➡️ заголовки запроса — http headers (передаются после строки запроса в виде пар "имя":"значение"). Обычно не сохраняются в логах, но иногда могут (можно настроить частичное сохранение — например, значение cookie или токенов точно не нужно сохранять, т.к. их можно использовать для выдачи себя за другого пользователя).

➡️ тело запроса — http body (тут понятно, это сами содержательные данные, которые мы передаем).

Есть из чего выбрать! Понятно, что идентификатор запрашиваемого ресурса мы обычно размещаем в пути, а содержимое помещаем в теле запроса (если это POST/PUT/PATCH). А если мы хотим указать связь нашего ресурса с другим? Например, связь заказов с клиентом? Тут уже могут быть два варианта: nested resources (вложенные ресурсы: /clients/689697/orders) или flat (плоские: /orders?client=689697, в API только пути с названиями ресурсов).

А если мы хотим указать версию API, у нас ещё больше вариантов: путь (/api/v1/orders), параметры (/api/orders?version=1) и заголовки (через кастомный заголовок: X-API-Version: 1, или через стандартный заголовок Accept: application/json; version=1 ). Я видел даже парочку случаев, когда версия передавалась в теле(!), даже для GET (хотя вообще сервер должен игнорировать тело GET-запроса).

Или, например, параметры пагинации. Тут у нас опять варианты: параметры, заголовок или тело. В пути не видел, но не исключаю — фантазия у людей безгранична.

Вопросы эти очень дискуссионные, я для себя выработал такие правила:

Путь — это указатель на коллекцию ресурсов или конкретный экземпляр. Лучше не тянуть туда ни версионность, ни фильтры, ни метаданные. Идентификатор в пути может быть только один (то есть, если мы описываем вложенные ресурсы, там может быть идентификатор на конце, или вторым от конца. Таким образом, вложенность будет только двухуровневая, и не будет диких URL типа /cities/77/pickpoints/35/clients/689697/orders/123456/items)

Параметры запроса — это ограничения на выдаваемую коллекцию ресурсов или набор полей одного ресурса. Поэтому тут будет простой поиск, фильтрация, набор полей в выдаче, пагинация, сортировка. То есть, это метаданные, относящиеся к ресурсу. Если мы хотим получить заказы клиента, доставленные в пункт выдачи с id=35, это будет выражено так: clients/689697/orders?city=77&pickpoint=35 (мы ограничиваем спискок заказов).

Заголовки — это метаданные запроса (а не ресурса). Это всё, что касается форматов выдачи (я видел API, в которых формат был зашит в путь: /api/xml/orders и /api/json/orders — не делайте так!), версии API и версии ресурса, кэша, параметров соединения, id запроса и т.п. Дискуссионный вопрос про пагинацию: её можно поместить и в заголовки тоже, как и ответную информацию (текущая страница, общее число страниц, число записей всего, следующая страница, предыдущая страница). Часто метаинформацию про пагинацию помещают в тело ответа, но, как по мне, это перегружает структуру ответа и может сделать её разнотипной для разных ответов — будьте с этим осторожнее.
Please open Telegram to view this post
VIEW IN TELEGRAM
Тело — непосредственно сам ресурс или коллекция ресурсов. Метаданные о ресурсе лучше отдать в заголовках ответа, хотя я вижу часто подходы, когда метаданные отдают в одном json'е с содержательными данными, как например, в спецификации JSON:API. Там у них вообще в ответе сразу и данные (data), и ошибки (errors), и метаданные (meta), и ссылки (links), и вложенные объекты (included):
{
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON:API paints my bikeshed!"
},
"links": {
"self": "http://example.com/articles/1"
},
"relationships": {
"author": {
"links": {
"self": "http://example.com/articles/1/relationships/author",
"related": "http://example.com/articles/1/author"
},
"data": { "type": "people", "id": "9" }
},
"comments": {
"links": {
"self": "http://example.com/articles/1/relationships/comments",
"related": "http://example.com/articles/1/comments"
},
"data": [
{ "type": "comments", "id": "5" },
{ "type": "comments", "id": "12" }
]
}
}
}],
"included": [{
"type": "people",
"id": "9",
"attributes": {
"firstName": "Dan",
"lastName": "Gebhardt",
"twitter": "dgeb"
},
"links": {
"self": "http://example.com/people/9"
}
}, {
"type": "comments",
"id": "5",
"attributes": {
"body": "First!"
},
"relationships": {
"author": {
"data": { "type": "people", "id": "2" }
}
},
"links": {
"self": "http://example.com/comments/5"
}
}, {
"type": "comments",
"id": "12",
"attributes": {
"body": "I like XML better"
},
"relationships": {
"author": {
"data": { "type": "people", "id": "9" }
}
},
"links": {
"self": "http://example.com/comments/12"
}
}]
}


Мне кажется, это уже перебор — каждый раз придется парсить ответ, чтобы вытащить оттуда нужное.

Тут надо принять решение, как вы действуете. Причем лучше на уровне компании, если у вас много API — чтобы они были единообразными. Я за чистоту: тело — для содержательных данных, заголовки — для метаданных, параметры — для ограничения содержания данных, путь — для указания понятий, которыми мы оперируем.

Let's discuss!
Сейчас будет сложный пост, я бы даже сказал — философский. На Flow в одном разговоре зашла речь о том, что различные документы и диаграммы — это разные проекции будущей системы. Мол, система многомерна и многоаспектна, и мы не можем её представить целиком, но можем создавать отдельные проекции, через эти проекции подсвечивать какие-то аспекты системы, и так приближаться к пониманию системы во всей ей полноте.

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

Мне кажется, в таком подходе есть большая доля идей позитивизма, даже логического позитивизма. Его адепты верили, что любое знание можно вывести и доказать либо путем эмпирических наблюдений (то есть, проверить на опыте), либо из логических правил и преобразований. Это идеи 20-30-х годов XX века, т.н. "Венский кружок". Дальнейшие разработки, в том числе членов кружка — Гёделя, например — привели к формальным доказательствам того, что истинность (и даже непротиворечивость) сложных систем доказать невозможно. Дальше больше — в квантовой физике обнаружился принцип неопределенности, в термодинамике — хаотические системы, в информатике — проблема остановки (принципиальная невозможность доказать — зациклится программа или выдаст ответ. в частности, это означает невозможность доказать наличие решений у некоторых уравнений).

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

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

В ту же ловушку позитивизма попала и разработка ПО — с идеей о том, что есть какое-то идеальное решение, удовлетворяющее всем требованиям, нужно только отыскать эти требования и это решение.

Точнее, разработка прошла все этапы:

метафизику, то есть разговор об очень абстрактных понятиях, не имеющих строгого содержания ("требование", "решение", "проект", "система", "данные");

позитивизм (мы можем всё определить, логически выразить и формально доказать);

постпозитивизм в виде фальсифицируемости (не можем доказать правильность программы, но хотя бы можем сказать, что те функции на тех данных, что мы проверили, работают корректно — тестирование и BDD), конструктивизма (не существует абсолютной истины, мы конструируем подходящий нам результат в процессе совместной деятельности, постоянно проверяя результат опытом; важна структура этой деятельности — agile), и неопрагматизма (нечто, что мы называем, имеет смысл, пока это несёт для нас пользу в определенном контексте; нет описания реальности "вообще", есть описание под конкретную задачу — DDD).

Окончательно добивает остатки позитивизма современный подход к ИИ: оказывается, при помощи "грубой силы" и наращивания числа связей в сети можно гораздо лучше решать практические задачи, чем через построение абсолютной исчерпывающей модели (см. очень показательную историю последних лет компании Abbyy и их проекта Compreno — чем она закончилась, я думаю, вы все слышали).

Наглядно видно это и в истории REST, например — тот же HATEOAS очень оптимистично выглядит в теории, а на практике почти не применяется.

В общем, пост философский, и каждому нужно понять для себя — какие представления я кладу в основание своей картины мира? Метафизику, позитивизм, или современные подходы — лишенные идеального образца, но зато решающие задачу.
Please open Telegram to view this post
VIEW IN TELEGRAM
Учат ли системному анализу в школе? Оказывается, да! В 10-11 классах. Есть вот целый учебник.

Системный анализ, в изложении авторов, представляет собой введение в системную инженерию (даже начинается с типового примера от системных инженеров — морской буровой платформы) + несколько расчетных упражнений по многокритериальному анализу.

Как думаете, поможет это в становлении системного аналитика? Оцените, кстати — на какую профессию там ориентируют школьников — генеральный конструктор, ни много ни мало!

Не знаю, правда, есть ли школы, в которых такой предмет реально преподают.
В этот день 56 лет назад, 9 декабря 1968, прошло событие, которое потом назвали "Мать всех презентаций" — 'Mother of All Demos'. Дуглас Энгельбарт продемонстрировал возможности своей системы NLS, oN-Line System.

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

Ещё раз: 56 лет назад, 1968 год. Компании ещё не все перешли на электронные терминалы, многие до сих пор для ввода и вывода используют перфоленты, люди считают на логарифмических линейках.

Презентация просто взрывала мозг! Да, это была экспериментальная система, но она оказала влияние на всё дальнейшее развитие технологий, появление и возможности персонального компьютера. Часть команды Энгельбарта потом перешла в Xerox, которая в 1973 выпустила персональный компьютер Xerox Alto — с мышью и оконным интерфейсом. Он вдохновил Стива Джобса на создание Macintosh, ну и так далее.

Алан Кей, тогда ещё студент магистратуры, был на презентации, проникся, потом в Xerox PARC придумал объектно-ориентированное программирование и язык Smalltalk.

Дэна Бриклина это демо вдохновило на создание VisiCalc — первого табличного процессора, дедушки Excel.
На презентации были и другие люди, о многих из которых теперь написано в Википедии.

Но главная идея, из которой все эти инструменты у Энгельбарта родились — расширение ментальных возможностей человека, ни много ни мало. Она опирается на статью ещё 40-х годов "Как мы можем мыслить" Вэнивара Буша.

В этом смысле интересно посмотреть на свои системы — исходим ли мы из того, что помогаем человеку мыслить?
Я смотрю, вам понравился пост про философию :) Тогда держите ещё один. Стэнфорд поддерживает ресурс "Стэнфордская философская энциклопедия", в частности, там есть раздел "Философия компьютерных наук".

В нем, например, предпринимается попытка разъяснить, что такое computer science — наука или инженерия?

Интересно, что тут опять возникает рационалистский оптимизм: сначала (с 1940-х до 1970-х) computer science рассматривалась, как подраздел математики: программа написана на формальном языке, значит, каждый оператор и их последовательность можно рассматривать как математическое выражение, в, конечном итоге, формально доказать правильность работы программы. Этим активно занимались Дейкстра и Хоар; и Дейкстра так протестовал против оператора GOTO в том числе потому, что тот мешал формальной верификации. Кроме того, Дональд Кнут поддерживал рассуждение, что компьютерная система — это творение человеческих рук, а значит её поведение может быть в точности предсказано.

В 1970-е, однако, системы стали действительно большими и получили развитые пользовательские интерфейсы, так что и свести все варианты входов системы к некоторому ограниченному множеству, и формально проанализировать все программы со всеми библиотеками стало нереальной задачей. Хотя теоретически это осуществимо (хотя бы и с некоторыми ограничениями), на практике сложность такой верификации на порядки превышала бы сложность создания системы. Поэтому методы computer science стали развиваться в сторону тестирования и оценки надежности или скорее достоверности (reliability), в чем-то походя на методы проверки качества физических изделий.

Хоть мы и не можем проверить работоспособность программы (а тем более комплекса программ) на всём объеме возможных входных данных и внутренних состояний, мы можем проверить некую выборку таких данных и состояний, наиболее статистически вероятных, и считать, что с некоторой вероятностью проверенная программа работает. В каком-то смысле, computer science — это инженерия математики — проверка математических выражений инженерными методами.

Наконец, computer science может рассматриваться как отрасль эмпирической науки — изучающей реально существующие вычислительные системы. Ну и что, что они созданы человеком и не найдено пока природных вычислительных систем — это такой специальный предмет исследования, который всегда создается человеком, но далеко не всегда человеком познаваем. Наверное, можно даже рискнуть назвать это эмпирической математикой — и рассматривать каждую новую систему, алгоритм или язык как своего рода эксперимент.

Ну, будем честными — почти всегда это эксперимент и есть — то ли система будет решать задачи, для которых она предназначена, то ли мы узнаем что-то новое о задачах, желаниях пользователя, вычислительных возможностях и о себе :)

А в следующий раз я расскажу о философских основаниях требований — там тоже интересно, не переключайтесь!
Please open Telegram to view this post
VIEW IN TELEGRAM
Продолжение истории про Mothers of All Demos — оператором видеокамеры на этом мероприятии был некий Стюарт Бранд — издатель журнала The Whole Earth Catalog, биолог, эколог и активист.

Стюарт был далек от компьютеров, но зато, например, убедил NASA сделать и опубликовать один из первых снимков Земли из космоса — чтобы показать людям, насколько она маленькая и хрупкая. Он же придумал ежегодно отмечаемый "День Земли"

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

А знаем мы его по одной очень известной фразе, популяризированной Стивом Джобсом:

Оставайтесь голодными, оставайтесь безрассудными!

Эта фраза была напечатана на последней странице The Whole Earth Catalog выпуска 1974 года, и именно её процитировал Джобс в речи перед выпускниками Стэнфорда, упомянув, что зачитывался этим журналом, и вообще это было "что-то типа Гугла на бумажном носителе, и задолго до Гугла".

Вот так всё связано хитрыми способами!
Иногда интересные общеприменимые идеи встречаются в стандартах и фреймворках, принятых в отдельных отраслях.

Так ISO 15926 начался в нефтегазовой индустрии, а сейчас считается общим стандартом для семантического представления 4D-модели (с учетом времени) любой сложной инженерной конструкции и её жизненного цикла в любой отрасли. Медицинский стандарт HL7 содержит самую подробную структуру для хранения личных имен, что мне только встречалась (из 11 полей и 13 типов).

А в образовании есть модель интеграции технологий в обучение (считай — уровень или глубина цифровизации) SAMR:

S — Substitution, простая замена старой технологии на цифровой эквивалент без изменения функции.
A — Augmentation, расширение — технология выполняет ту же функцию, но с небольшим расширением.
M — Modification, изменение — технология значимо меняет способ выполнения функции.
R — Redefinition, переопределение — применение технологии позволяет выполнить совсем другую задачу, ранее непредставимую.

На примере такси:

S — раньше такси вызывали по телефону в конкретной компании-перевозчике, теперь можно вызвать через мессенджер/чат-бот/форму на сайте (таксисту вызов передает оператор по рации);

A — На сайте можно посмотреть историю своих заказов и текущий заказ;

M — Можно вызвать такси в мобильном приложении перевозчика, адрес определяется автоматически, у таксиста тоже есть приложение, где он видит вызов, оператор не нужен;

R — Каждый может стать таксистом, если есть своя машина и немного свободного времени. Не нужно знать контакты конкретного перевозчика — пользователь вообще не думает, кто и из какой конкретно компании приедет. У всех пассажиров и всех таксистов приложение одного координатора. Кто бы мог такое придумать!

У нас уровень трансформации обычно измеряют другими ступенями: компьютеризация, информатизация, цифровая трансформация (поставили компьютеры и начали на них решать какие-то задачи; создали интегрированную систему для поддержки бизнес-процессов; перестроили бизнес-процессы, и каждый новый сразу проектируем в цифре). Иногда говорят про перестройку бизнес-модели на последнем шаге. это уже ближе к SAMR. В другом подходе последний уровень почему-то "мышление на основе данных", что бы это ни значило. Redefinition мне больше нравится!

Вы тоже, когда автоматизируете процессы, задумайтесь — чем вы занимаетесь? Заменой, расширением, изменением или переопределением?

Аналитик, особенно бизнес-аналитик, по моему убеждению занимается именно цифровизацией предприятия — может быть, не всего, а отдельных процессов, но в пределе — может и всего, как CDTO (директор по цифровой трансформации). Это к вопросу о возможном карьерном треке и кем может быть опытный аналитик, если не архитектором и не менеджером проектов.
Мы всё неправильно понимаем про HTTP метод PATCH.

Иногда читать стандарты очень увлекательно — становится понятно, что люди имели в виду на самом деле. Читать книги и статьи опаснее — там уже личные интерпретации, кто как понял. Почти во всех примерах, что мне встречались, тело запроса PATCH описано, как набор новых значений полей в JSON — с оговоркой, что в случае PUT мы должны были бы передать все поля, а не только изменившиеся, а в случае PATCH — только изменившиеся.

Но в стандарте — RFC 5789 — написано совсем другое! В запросе PATCH должен передаваться набор изменений, применяемых к ресурсу, в формате "патч-документа". Что это за формат — зависит от медиа-типа ресурса. В реестре медиа-типов IANA есть, например, типы патч-документов для json: application/json-patch+json и application/merge-patch+json; и тип для XML: xml-patch+xml (ну ещё несколько специфических).

Документ JSON-patch [RFC 6902] выглядит именно как набор операций, вносящих изменения в JSON:

   [
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]


op — это, понятно, название операции, вот какие операции могут быть:

add — добавить элемент в массив или свойство в объект;
remove — удалить свойство объекта или элемент массива;
replace — соответственно, заменить (как последовательное применения remove и add);
move — переместить значение из одного места (пути) в другой (тоже как remove и add, но у add будет другой путь);
copy — скопировать значение и вставить в другое место;
test — проверить значение по указанному адресу на соответствие (без масок или регулярных выражений, просто на совпадение).

Понятно, что неидемпотентным PATCH делает именно операция add — если будем применять её несколько раз к массиву, добавится много элементов вместо одного.

То, как обычно описывают формат применения PATCH — больше похоже на merge-patch+json: там мы действительно передаем только изменившиеся свойства, и null для тех свойств, которые хотим удалить.

В любом случае, тип медиа не должен быть просто application/json — по стандарту (а точнее — по errata к стандарту, списку исправлений), сервер вообще должен возвращать ошибку 415, если в запросе PATCH приходит тот же медиа тип, что у ресурса — то есть, не json-patch, просто json. Это чтобы избежать неоднозначности интерпретации. А в каких форматах сервер готов принимать патч-документ — он должен сам сказать в ответе на запрос OPTIONS: Accept-Patch: application/prs.example.patch+json, application/json-patch+json, application/merge-patch+json.

Вот так PATCH должен работать на самом деле. Ясно, что он так практически никогда не работает, так что можете этими знаниями блеснуть на собеседовании, разве что. И то — будьте осторожны, а то интервьюер примет вас за зануду-теоретика, выучившего стандарты, но далекого от практики. А на практике ни один фронтендер не будет вам конструировать сложный патч-документ, когда можно передать просто набор изменившихся полей. Ну, или пока дело не дойдет до какого-то очень сложного по структуре, со многими уровнями вложенности объекта.
По сети, говорят, ходит флешмоб про 20 книг, которые до сих пор с вами или сильно повлияли на вас: без объяснения, только обложки.

Вот мои 20 (это те, что "по специальности"). Удивительно тут, конечно, что по системному анализу и управлению требованиями книг тут не так много — даже не понятно, откуда я этого всего нахватался.