Обновить

Поколение JSON: цена удобных абстракций и упадок культуры ресурсов

Уровень сложностиСредний
Время на прочтение8 мин
Охват и читатели13K
Всего голосов 40: ↑36 и ↓4+39
Комментарии62

Комментарии 62

А это нынче тоже называется "однострочником". Нормальное явление, когда нагромождение уровней стэка дает вот такую вот иллюзию простоты. Казалось бы, какие проблемы и ошибки могут быть в таком коде? Вот же он, очень простой, легко читается!

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

Ой ой, ну конечно.

Если оно такое уж большое, то и покажите этот стек вызовов, поймет наверное о чем речь идет.

А используют за тем, что там наверняка сотня оптимизаций кем то продуманы.

Да. Опитимизированны и уже придуманны.

Смысл данной статьи в том. Что из - за не знания основ. Начинается полное отсутствие понимания, как сделать приложение удобней пользователю. Менее русурсоёмким для сервера.

Что актуально, ибо закон Мура перестал работать, а требования растут по экспоненте.

Так ведь все и правда придумано и оптимизировано, только основы тут не при чем.

Не надо быть капитаном очевидностью, что бы понимать что выборка лишнего поля выбирает лишнее поле.

Ну только вот человек вполне доступно расказал, почему ваши оптмизации не сработают, потому-что невозможно оптимизровать код в различных компонентах одного стэка. Это еще не говорю о том, что не происходит удаление неиспользуемого кода. Когда вы ставите зависимость или подключаете библиотеку, то подключает ВСЕ, даже если из этого вам нужна только функция, которую можно в 1кб машинного кода запустить. Там мы втыкаем библиотеку, тут мы фигак, сразу получаем + 10Мб. А сколько кода из этого не задействуется ВООБЩЕ? 90%? Что, скажете не так?

10 мб лишнего кода ныне и правда считать не стоит.

10 мб лишней передачи - это да, такое себе.

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

Вот бы человечество придумало что-то вроде анализатора, который бы находил неиспользуемый код в библиотеках (и в пользовательском коде тоже можно, кстати) и удалял из скомпилированного артефакта. Можно даже придумать какое-нибудь прикольное название, например, tree shaking. Тогда не станет проблемы +10 Мб, а библиотеки останутся полезными.

Забыли /s

/me вздыхает

Вы правы :)

Извинити, конечно, но человечество давно это всё придумало в нормальных языках программирования.

Статья говорит о проблеме фокусируясь в основном только на одной из причин - некомпетентности разработчика. Тогда как половина причин, а может и больше это хотелки бизнеса или внутренняя парадигма организации. Разработчик может и хочет что-то там ускорить, но всегда ли ему дадут это сделать?

На рынке конкуренция и надо выпустить MVP быстрее конкурентов? - Нафиг оптимизацию, делаем рабочий прототип на %известный фреймворк% и в продакшн. Оптимизируем потом с ростом нагрузки.

Клиенты жалуются на тормоза приложения? - Подтяните основные метрики. Если надо добавим ресурсов.

70% запросов жрет аналитика? - Ну простите уж, нам надо собирать много, много данных.

Надо провести рефакторинг и пересмотр архитектуры чтобы через пару лет все не навернулось? - Вы о чем вообще? Как я своему менеджеру прокину лишние расходы которые не принесут прибыль в текущем квартале? У нас вообще-то план есть!

А потом в Gmail тормозит интерфейс так, словно они майнят на клиенте крипту.
Не думаю что в Google работают отбитые вчерашние ученики курсов, которые не могут посмотреть вне абстракции.

Хотя, причем тут ученики курсов.
Тут затрагиваются архитектурные вопросы, к которым у джунов по идее не должно быть доступа. Джун не должен проектировать структуру БД. Это задача сеньора, который потом должен бить по рукам тех, кто пишет херовый код или запросы.

Надо провести рефакторинг и пересмотр архитектуры чтобы через пару лет все не навернулось? - Вы о чем вообще? Как я своему менеджеру прокину лишние расходы которые не принесут прибыль в текущем квартале? У нас вообще-то план есть!

Горизонт планирования менеджеров просто крошечный. Да и текучка у них... Я пережил уже троих на этом месте

Вернем ассемблер в массы! Пусть каждый джун перед запросом в базу напишет драйвер сетевой карты

Ну, это уже впадение в другую крайность. Обе эти крайности деструктивны.

Вы очень точно подметили про "иллюзию простоты". Никто не призывает возвращаться к ручному управлению памятью везде и всюду, но вот эта потеря связи между "написал строчку" и "понял, что произошло под капотом" действительно пугает. Рад, что мы на одной волне!

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

А причем тут фронтэнд? Это общая проблема. Кроме брюзжания решение есть - бороться за эффективность кода. Не за мелкие низкоуровневые оптимизации, но чтобы человек не только умел использовать какой-то код, но и понимал побочные эффекты. Как элемента культуры, мне кажется - очень хорошо. Гораздо лучше чем стимулировать подход в стле "фигак-фигак и в продакшен". Вы можете сказать что не все могут такое себе позволить (дедлайны, ограниченный бюджет), и будете частично правы. Но если не начинать, то это никогда не станет привычкой, а вот это "фигак-фигак" будет рассматриваться как норма. Типа работает, и ладно. Согласитесь что ситуация "работает быстро, занимает мало места" гораздо прикольнее чем "работает на грани допустимого, занимает много, но ничего, купим еще сервера". Первый путь - путь добра ))) Ну согласитесь..

Т.е. Вы призываете работать "за идею" над проектами, за которые платят как за "... и в продакшен"?

Категорически не согласен, то, что вы называете путем добра - это преждевременная оптимизация и это путь зла. Сколько я таких мердж реквестов видел... Разработчик напишет, навертит и в итоге вместо 3х строчек кода я вижу 5 классов с кучей методов, я спрашиваю:

- Зачем?

- А вот когда у нас будет нагрузка, да 5 микросервисов, да шардинг бд...

- Ну щас же у нас такого нет, когда будет нагрузка, тогда и перепишем на твой варинт, а щас у тебя 5 классов по 3 метода в каждом вместо 3х строчек кода

- Ну нет, ну всё равно же, ну у меня же выдуманный мною мир рушится...

Оптимизация должна преследовать какую-то цель. Например, приходит бизнес и говорит: мы сделали исследование дизайна и обнаружили, что у нас страница грузится 500мс, часть пользователей не дожидается всей загрузки и уходит со страницы, если сократить загрузку до 5мс, то мы значительно повысим посещаемость. Разработчики: ок, переписываем на rust-е. У вас же цель, чтобы вам было прикольно, потому что вас триггерят слои абстракции и размер приложения - цель, которая нужна только вам и больше никому.

Микрооптимизации и переписывание на Rust ради 5мс без бизнес-цели – это зло. Но в статье речь не о преждевременной оптимизации, а о базовой инженерной гигиене. Спроектировать API так, чтобы он не отдавал клиенту пароли, внутренние ID базы и лишние 50 полей, которые не используются на экране – это не "наворот", это нормальный дизайн. Чинить это потом, когда база ляжет от рекурсивных джойнов, а клиенты начнут жаловаться на лаги – обойдется бизнесу в десятки раз дороже.

Спроектировать API так, чтобы он не отдавал клиенту пароли, внутренние ID базы и лишние 50 полей, которые не используются на экране – это не "наворот", это нормальный дизайн.

Это прописные истины — буквально «нормально делай, нормально будет», что тут принципиально нового? При чем тут несчастный JSON и сериализация?

«Поколение JSON» (которому 25 лет, кстати), «что мы сломали в IT» (регулярно ломаем, кстати), «раздутый софт» (его раздувают инженеры, или бизнес, кстати?), «npm-зависимости» (шуткам про размер node_modules уже сто лет в обед, кстати) — это все, конечно, плохо, но про это (и как с этим бороться) примерно все давно в курсе.

И даже статьи с одной-единственной целью «подпишитесь на мой X, и скачайте оттуда бесплатный Y, пока не случилось Z» — тоже давно не новая тема.

Спасибо, что бесплатный, кстати!

Какое решение, кроме брюзжания?

Время идет, а старики всё также брюзжат на тему раньше было лучше.

И вот был разработан первый компилятор. Эту программу назвали Assembler, что переводится как "сборщик". Писать на нем практически так же сложно, как и в машинных кодах, однако теперь уже использовались не числа, а понятные, как показано на рис. 1.5, человеку слова.Теперь все та же команда копирования регистров выглядела так: mov eax, ebx. Да, код на ассемблере не совсем нагляден, но зато намного удобнее, чем то же самое, но в машинных кодах. Вроде все прекрасно и удобно, но почему-то среди программистов возникли споры и разногласия. Кто-то воспринял новый метод с удовольствием. А кто-то говорил, что машинные коды лучше, что программа, написанная в кодах, работает быстрее. Говорят, что эти споры доходили до драк и иногда лучшие друзья становились врагами.

Библия Delphi, 2007й год.

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

Ну так-то не всякая байтовая логика полностью представима на ассемблере, например если некая процедура начинается с байтов A9 06 2C A9 07 2C A9 08 и в разных частях кода существуют переходы на каждый из A9 (при этом команда A9 XX интерпретируется как lda #XX, а 2C XX YY как нечто незначимое), то это будут три процедуры с разными инициализированными значениями аккумулятора и общей последующей логикой и один и тот же байт A9 перед 08 будет выступать в разных ролях

Сказки венского леса. Во-первых, "eax,ebx" появились на два, если не три десятилетия позже ассемблера. Во-вторых, ни разу не видел чтобы кто-то утверждал что в кодах программа быстрее. Хотя сам когда-то в кодах писал.

Там еще забавный черри-пикинг фактов - когда мы хотим показать CPU(или latency) то мы учитываем сжатие json портянок. Когда мы считаем сколько лишнего egress в рублях тратится то про сжатие чудесным образом забываем.

Gzip действительно отлично жмет повторяющиеся ключи в JSON, и реальный egress-трафик будет меньше 'сырых' мегабайтов. Но проблема в том, что уникальные текстовые данные, вложенные структуры и избыточные метаданные (те же длинные токены, id и лишние base64) сжимаются хуже. К тому же, чем больше мы сэкономили на трафике за счет gzip, тем больше тактов CPU смартфона мы сожжем на декомпрессию этого "жира" перед тем, как отдать его парсеру. Так что за мусорные данные мы всё равно платим: либо рублями провайдеру, либо батареей пользователя.

Если размер JSON вырос до мегабайтов, значит проблема не в формате передачи.

Дык суть не в JSON. JSON в данном случае это лишь демонстрация одного из наглядных кейсов. Если DTO'ха выростает до мегабайтов то в большинстве случаев это алерт, и не важно JSON это или JSONB или вообще это какой-либо другой, пусть даже очень компактный формат.

Помню времена, когда вместо JSON обычно начинали городить "самопальные" форматы с конкатенацией данных через разделитель - со всеми сопутствующими багами, костылями и благополучной оссификацией уже через 2-3 релиза. А то и какой-нибудь CORBA/DCOM с тайплибами и IDL-компайлерами, если разрабы оказались поэнтэрпрайзнее да помускулистее.

Поэтому когда Microsoft выкатил LSP с просто HTTP и просто JSON-ками, то только тут, наконец, и вздохнул спокойно.

Ну собственно дофига же нормальных быстрых бинарных СТАНДАРТНЫХ форматов, которые очень быстро парсятся и не уступают JSON в гибкости. Хотя и JSON можно варить по-разному. Можно отдавать сразу всю базу по каждому чиху (бывает и такое), а можно получать на каждый момент времени только необходимую информацию.

Но все-же автор не столько ругает JSON, сколько сетует на то, что люди часто не понимают что за всем этим стоит и сколько ресурсов стоит то или иноге архитектурное или техническое решение. Мы привыкли писать код "который работает" и уже мало кто знает, что там внутри происходит. Это часто наблюдается у молодых. Но раньше это с опытом как-то нивелировалось, люди с опытом вникали (были вынуждены) а вот последнее поколение вообще не вникает. Это да, своего рода такой вайбкодинг: "я пишу, а оно там магию делает какую-то и мне вообще не интересно как".

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

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

Вы никак не отнимите у JSON его огромный плюс - он поддерживается практически любым языком программирования, можно читать даже на тостере или утюге. Так уж сложилось. Поздно брюзжать про бинарные СТАНДАРТНЫЕ форматы.

При этом гугл продолжает развивать свой protobuf.

Очевидно, что JSON - good enough, он не идеален и подходит не во всех ситуациях.

Вот, вот. Я сам из тех кто начинал программировать еще до DOS, и у меня многие оптимизации уже на автомате пишутся. Они для меня не оптимизации - я просто так думаю и пишу. Но, сколько раз ловил на ревью от молодых коллег, причем достаточно компетентных: "ты занимаешься преждевременной оптимизацией". Только вот для меня зачастую не "заниматься преждевременной оптимизацией" несет большую когнитивную нагрузку - плохо написать надо еще подумать как :)

Это же палка о двух концах. Допустим ты дефолт разраб у кабаныча. Как объяснить кабанычу, что ты будешь писать фичу не день, а N дней, просто потому что ты хочешь написать ее нормально, при этом результат будет чуть лучше, а не в N раз?

Автопосадка из космоса звучит конечно грандиозно, но на деле это всего лишь решение диффура (формулку запрогать)

Секрет в том, что бизнесу (или "кабанычу") не нужно продавать "красивую архитектуру". Ему нужно продавать метрики и деньги. Если фича, написанная за 1 день, заставляет приложение тормозить на бюджетных Android-смартфонах, конверсия падает, и бизнес теряет деньги. Плюс, не отдавать на фронт всю таблицу из БД вместе с техническими и неиспользуемыми на клиенте полями – это не N дней работы, это просто грамотно написанный DTO/сериализатор, который пишется за те же 15 минут, но экономит мегабайты.

Я конечно сильно извиняюсь, но при чём тут бриджи если вы просто парсите JSON?
Этим занимается hermes или v8 (в классическом варианте), бриджи - это когда вы этот уже скорее всего распарсенный JSON передаёте нативному компоненту или модулю (который ловит его в виде NSDictionary или ReadableMap если ведроид).

Вы правы в деталях механики. Парсингом действительно занимается JS-движок (Hermes/V8). Но проблема возникает как раз на стыке: когда нам нужно прокинуть этот огромный массив данных для рендера списков на нативную сторону. В старой архитектуре это приводило к сериализации/десериализации при переходе через мост. В новой JSI (которую я упоминаю) это решается ссылками на C++ объекты, но аллокация огромного количества памяти под "мусорные" поля из ответа всё равно нагружает GC и съедает ресурсы процессора.

Насколько я помню всё-таки не совсем так, сериализировал только ios, а для андроида там вроде был какой-то конвертер из V8::Object в колхозный ReadableNativeMap прикручен, ну да не суть - разумеется когда некоторое особо талантливые разработчики пытались запихнуть в нативный компонент весь стейт редакса мегабайт этак на 10, это было весело при любой имплементации. Помню один гениальный проект где товарищи очень жаловались а чего это у нас нативный компонент такой плохой что только через пару секунд на изменение стейта реагирует (почти 10 лет назад история была, ещё до реактно-функционального треша, сейчас оно б ещё веселее у них работало).

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

А какую проблему мы вообще решаем?

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

Зачем?

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

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

Хотя я знаю «Зачем» была написана статья - ради рекламы тг канала

Хорошая статья про ответственность 👍

Автор книги Поколение JSON

А есть возможность получить автограф на бумажном экземпляре?

Спасибо за интерес! Да, конечно. Напишите мне в личку здесь или в Telegram (ссылка в профиле) — договоримся, как это лучше организовать, с радостью подпишу.

Сегодня сам получил печатный экземпляр, проверял как сервис печати по требованию работает. В целом неплохо.

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

Именно) JSON – прекрасный инструмент. Формат ни в чем не виноват. Виновато отношение, при котором "раз это текст и он гибкий, значит можно запихивать в него вообще всё подряд без разбора, фронтенд сам отфильтрует". Об этом и речь.

А какая простая альтернатива этому ? gRPC ? А как тогда дружить то что физически не дружится ? JSON потому и удобен что все что угодно можно сериализовать в него и десериализовать из него . Ну а про скорость , не надо в запросе 5 тысяч объектов из базы данных получать единоразово , и все.

Мне кажется спор JSON vs gRPC это вечная ложная дилемма. Проблема почти всегда в том, что эндпоинт превратился в свалку всего подряд

Смешали все в кучу. V8 парсит мегабайты JSON за миллисекунды. Свистопляска начинается не из-за самого формата, а когда вы пытаетесь засунуть весь этот массив данных в React-компоненты и вызываете каскад лишних ререндеров DOM-дерева

Это просто автор постеснялся упомянуть, что иногда можно даже и без React'а :)

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

Но последнее время я чаще задумываюсь - а сколько времени (и, соответственно, денег) съест эта оптимизация? Например, мы сэкономим 4 тысячи в месяц на инфраструктуре, но при этом оптимизация будет стоить 2 недели опытного разработчика (200к+ с учетом налогов). Имея эти цифры перед глазами уже можно решать, что выгодней в текущих условиях. И, к сожалению, большую часть оптимизаций оказывается выгодней закрыть увеличением ресурсов.

4к в месяц экономии легко убиваются одной неделей разработки, тут математика беспощадная

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

...и забыть о начальном абзаце в комментарии. :-)

"Собственное одобрение стоит сотни чужих, а как его заслужить — никто не знает "

Оптимизация должна преследовать какую-то цель.

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

Нормально работает только когда есть лимиты на размер ответа и мониторинг, иначе любой API со временем распухает

Считаю JSON отвратительным протоколом для пердачи данных. Вы вообще видили как он передаёт байтовые масcивы? Это просто ужас оверхеда. Он превращает их в base64. Вы даже строку нормально передать не сможете. Например в С# используется UTF-16. JSON UTF-8 и главное всю строку надо ещё пройти и заэкранировать.

К чему это я? А к тому что написать протокол который бы не имел этих недостатков - 10 минут. int количестиво переменных. 1 байт тип переменной. По типу определяешь длину переменной. Для массивов и стрингов добаляешь int длины. Всё! Хотите вложенные объекты - ну чуть усложнить. Ах да забыл. На имена переменных тоже по ushort добавить - длина имени. Ну и имя переменной в голых байтах. Это работает максимально быстро без какого либо оверхеда. WEB спокойно перекидывает данные в бинаром виде - нет никаких ограничений на только ASCII символы.

Я хз кому надо смотреть протоколы в сыром виде. Тем более JSON в сыром виде тоже шляпа та ещё - всё в одну строку. В любом случае парсить надо для наглядности. Так вот парсер для протокола который я описал выше - пишется не за 10 минут а за 5.

Поколение JSON

Когда настанет время "Поколения JSON-LD"?

Более приземленные вопросы. Обычно делаю единый код на браузерном JS для работы как на github (иной), так и локально (desktop). И тут конечно же натыкаюсь на "ужасный CORS". Есть какие-то рекомендации, как делать единый код для обхода CORS? Например, файлы конфигураций config.json оборачиваю в config.js. Как-то можно ошибки fetch() или как-то иначе загружать файлы (или только определять откуда и делать разные ветки в коде, если desktop, то с подтверждением пользователя)?

Не про json, а к "Они прорубаются через 7 слоёв инфраструктуры:". В том же проекте
была проблема с
<script src="https://cdn.sheetjs.com/xlsx-0.20.2/package/dist/xlsx.full.min.js"></script>

Ошибка: файл XLSX is not defined

Особенно с мобильного инета постоянно нужно было жать несколько раз кнопку "обновить". Как решение - поместил xlsx.full.min.js в папку проекта (заработало), но может быть есть более грамотный выход (или объяснение)?

Не понимаю последнее время такие статьи на хабре. Ну при чем тут json то. Автор, читайте литературу, всё написано уже

Ушло уже время, когда такие статьи были актуальны.

Мы не должны возвращаться к 128 КБ. Но, кажется, нам пора вернуть себе тот уровень инженерной ответственности, который был у создателей «Бисера-4»

Ну, с текущими ценами на оперативку, есть вероятность пересмотра приоритетов. Правда для этого нужна ситуация, что кратно увеличится потребность в ресурсах и придется как-то решать проблему ресурсов.

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

Как и денег есть инфляция, такая же инфляция есть у технических систем. Тогда требование было одной – она работала корректно. Современные системы имеют огромный список требования, где помимо работоспособности, есть еще требования к безопасности, к подержке, стоимости и времени разработке, многопточности и т.д. А сверху еще слой бизнесовых правил – что мы должны хранить, логировать, что и как передавать и т.д. И при всем при этом система должна быть спроектирована так, чтобы можно было вести паралельную разработку в разных командах и делать это максимально быстро. Да, злые менеджеры со своими метриками.

И при этом, те самы абстракции, которые позволили относительно быстро подключать людей к проекту и получать рабочие системы, не погружая человек глубоко в контекст. Шины, орекестраторы, медиатор, сто пятьсот паттернов и т.д. – все это раздувает и бэкенд, но при этом делает его устойчивым к развитию сервиса, систему не пишут один раз под одну конкретную задачу. А в 128 кб уверен влезло 10050 if, вызовов goto и регулярных переключений указателей памяти и ее очистки.

Мы используем текстовый формат для общения двух частей одной программы внутри одного процессора.

Простите моё невежество, но как мы к такому пришли? Я из мира промавтоматики, я не понимаю, как можно просто так забить на ресурсы и гонять джейсоны, когда у вас общая память. Почему не shared memory?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации